lex-llm-vertex 0.1.4 → 0.1.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 +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +50 -1
- data/lex-llm-vertex.gemspec +1 -1
- data/lib/legion/extensions/llm/vertex/provider.rb +49 -4
- data/lib/legion/extensions/llm/vertex/version.rb +1 -1
- data/lib/legion/extensions/llm/vertex.rb +15 -22
- metadata +3 -7
- data/lib/legion/extensions/llm/vertex/registry_event_builder.rb +0 -93
- data/lib/legion/extensions/llm/vertex/registry_publisher.rb +0 -100
- data/lib/legion/extensions/llm/vertex/transport/exchanges/llm_registry.rb +0 -24
- data/lib/legion/extensions/llm/vertex/transport/messages/registry_event.rb +0 -42
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 524d4e5a1420c6a145c89da553e021205e5447c462509b4397161b01d8c37ed6
|
|
4
|
+
data.tar.gz: 4b6afd972ba22dacbcfd844287ee8828bfefa05cdce2a13ec2ff052f7fdb28b0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6b309e1328f525cb652fb0cf9d2f4515d6092a0283d75f7240ea514e978612268613ac5c1ee06333c8fb38161cd613423c7c25b03322de3d98eb9d5f2c9c2bea
|
|
7
|
+
data.tar.gz: c78952b334fc28d106b02101585863c062d31c1069652688f0dfb93b8151d923e20efb1ac600f73ca0be98213dd92ffc368db6c992d380fbd22d6d144c40ad69
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.1.5] - 2026-04-30
|
|
4
|
+
|
|
5
|
+
- Add `Legion::Logging::Helper` to all modules and classes for structured logging
|
|
6
|
+
- Replace ad-hoc `log_publish_failure` with `handle_exception` in RegistryPublisher
|
|
7
|
+
- Add `handle_exception` to every rescue block with correct level, handled, and operation
|
|
8
|
+
- Add info-level logging for key provider actions: chat, stream, embed, count_tokens, discover_offerings, health
|
|
9
|
+
- Update README to reflect current architecture, file map, and observability conventions
|
|
10
|
+
|
|
3
11
|
## [0.1.4] - 2026-04-30
|
|
4
12
|
|
|
5
13
|
- Add headers: parameter to complete method for base provider contract compliance
|
data/README.md
CHANGED
|
@@ -48,6 +48,18 @@ provider.count_tokens(messages, model: model)
|
|
|
48
48
|
|
|
49
49
|
`discover_offerings(live: false)` returns a conservative static catalog for routing defaults and unit tests. `discover_offerings(live: true)` calls the Vertex publisher models listing endpoint and maps returned model data into `Legion::Extensions::Llm::Routing::ModelOffering` records.
|
|
50
50
|
|
|
51
|
+
## Static Model Catalog
|
|
52
|
+
|
|
53
|
+
| Model | Alias | Publisher | Family | API Mode |
|
|
54
|
+
|-------|-------|-----------|--------|----------|
|
|
55
|
+
| gemini-2.5-flash | gemini-flash | google | gemini | generateContent |
|
|
56
|
+
| gemini-2.5-pro | gemini-pro | google | gemini | generateContent |
|
|
57
|
+
| gemini-embedding-001 | gemini-embedding | google | gemini | predict (embedding) |
|
|
58
|
+
| text-embedding-005 | text-embedding | google | gemini | predict (embedding) |
|
|
59
|
+
| claude-sonnet-4-5 | claude-sonnet | anthropic | anthropic | rawPredict |
|
|
60
|
+
| mistral-medium-3 | mistral-medium | mistralai | mistral | rawPredict |
|
|
61
|
+
| llama-4-maverick | llama-4-maverick | meta | meta | rawPredict |
|
|
62
|
+
|
|
51
63
|
## Model Offerings
|
|
52
64
|
|
|
53
65
|
Every offering uses:
|
|
@@ -60,6 +72,30 @@ Every offering uses:
|
|
|
60
72
|
|
|
61
73
|
Known aliases are intentionally small and configurable. For example, `gemini-flash` resolves to `gemini-2.5-flash`, while the offering preserves `projects/{project}/locations/{location}/publishers/google/models/gemini-2.5-flash`.
|
|
62
74
|
|
|
75
|
+
## Registry Events
|
|
76
|
+
|
|
77
|
+
When transport is available, the `RegistryPublisher` publishes best-effort readiness and offering availability events to the `llm.registry` topic exchange using `lex-llm` registry envelopes. Events are published asynchronously in background threads and never block the caller.
|
|
78
|
+
|
|
79
|
+
## File Map
|
|
80
|
+
|
|
81
|
+
| Path | Purpose |
|
|
82
|
+
|------|---------|
|
|
83
|
+
| `lib/legion/extensions/llm/vertex.rb` | Namespace module, default settings, provider registration |
|
|
84
|
+
| `lib/legion/extensions/llm/vertex/provider.rb` | Vertex AI provider: chat, stream, embed, count_tokens, health, discovery |
|
|
85
|
+
| `lib/legion/extensions/llm/vertex/registry_publisher.rb` | Async best-effort llm.registry event publisher |
|
|
86
|
+
| `lib/legion/extensions/llm/vertex/registry_event_builder.rb` | Builds sanitized registry event envelopes |
|
|
87
|
+
| `lib/legion/extensions/llm/vertex/version.rb` | `VERSION` constant |
|
|
88
|
+
| `lib/legion/extensions/llm/vertex/transport/exchanges/llm_registry.rb` | `llm.registry` topic exchange definition |
|
|
89
|
+
| `lib/legion/extensions/llm/vertex/transport/messages/registry_event.rb` | Transport message for registry events |
|
|
90
|
+
|
|
91
|
+
## Observability
|
|
92
|
+
|
|
93
|
+
All modules and classes use `Legion::Logging::Helper` for structured logging:
|
|
94
|
+
|
|
95
|
+
- **Info-level logging** on key provider actions: `chat`, `stream`, `embed`, `count_tokens`, `discover_offerings`, `health`, and registry publish operations
|
|
96
|
+
- **Every rescue block** calls `handle_exception(e, level:, handled:, operation:)` with dot-separated operation names (e.g. `vertex.provider.health`, `vertex.registry.publish_event`)
|
|
97
|
+
- **Level conventions**: `:warn` for recoverable failures, `:error` for unexpected errors, `:debug` for expected/best-effort failures (transport unavailable, etc.)
|
|
98
|
+
|
|
63
99
|
## API Contract
|
|
64
100
|
|
|
65
101
|
The implementation is intentionally limited to Vertex AI REST surfaces documented by Google Cloud:
|
|
@@ -71,7 +107,20 @@ The implementation is intentionally limited to Vertex AI REST surfaces documente
|
|
|
71
107
|
|
|
72
108
|
Provider-specific request bodies are not guessed. Partner raw-predict chat requests use the message shape documented for those partner model endpoints; embeddings are only implemented for documented Vertex text embedding models.
|
|
73
109
|
|
|
74
|
-
|
|
110
|
+
## Development
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
bundle install
|
|
114
|
+
bundle exec rspec # 0 failures
|
|
115
|
+
bundle exec rubocop -A # auto-fix
|
|
116
|
+
bundle exec rubocop # lint check
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## License
|
|
120
|
+
|
|
121
|
+
Apache-2.0
|
|
122
|
+
|
|
123
|
+
## References
|
|
75
124
|
|
|
76
125
|
- [Vertex AI GenAI REST API](https://cloud.google.com/vertex-ai/generative-ai/docs/reference/rest)
|
|
77
126
|
- [Generate content with the Gemini API in Vertex AI](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/inference)
|
data/lex-llm-vertex.gemspec
CHANGED
|
@@ -26,5 +26,5 @@ 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.
|
|
29
|
+
spec.add_dependency 'lex-llm', '>= 0.2.0'
|
|
30
30
|
end
|
|
@@ -56,7 +56,7 @@ module Legion
|
|
|
56
56
|
def capabilities = Capabilities
|
|
57
57
|
|
|
58
58
|
def registry_publisher
|
|
59
|
-
@registry_publisher ||= RegistryPublisher.new
|
|
59
|
+
@registry_publisher ||= Legion::Extensions::Llm::RegistryPublisher.new(provider_family: :vertex)
|
|
60
60
|
end
|
|
61
61
|
|
|
62
62
|
def resolve_model_id(model_id, config: nil)
|
|
@@ -112,14 +112,25 @@ module Legion
|
|
|
112
112
|
"#{publisher_model_path(model)}:#{suffix}"
|
|
113
113
|
end
|
|
114
114
|
|
|
115
|
+
def list_models
|
|
116
|
+
log.info { 'listing available Vertex models from static catalog' }
|
|
117
|
+
STATIC_MODELS.map { |entry| model_info_from_static(entry) }.tap do |models|
|
|
118
|
+
log.info { "discovered #{models.size} Vertex model(s); publishing to registry" }
|
|
119
|
+
self.class.registry_publisher.publish_models_async(models, readiness: readiness(live: false))
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
115
123
|
def discover_offerings(live: false, **filters)
|
|
124
|
+
log.info { "discovering offerings live=#{live} project=#{project} location=#{location}" }
|
|
116
125
|
return static_offerings(**filters) unless live
|
|
117
126
|
|
|
118
127
|
response = connection.get(models_url)
|
|
119
128
|
models = response.body['publisherModels'] || response.body['models'] || []
|
|
120
|
-
models.map { |model| offering_from_live_model(model) }
|
|
121
|
-
|
|
122
|
-
|
|
129
|
+
offerings = models.map { |model| offering_from_live_model(model) }
|
|
130
|
+
log.info { "discovered #{offerings.size} live offering(s) from Vertex" }
|
|
131
|
+
model_infos = offerings.map { |o| model_info_from_offering(o) }
|
|
132
|
+
self.class.registry_publisher.publish_models_async(model_infos, readiness: readiness(live: false))
|
|
133
|
+
offerings
|
|
123
134
|
end
|
|
124
135
|
|
|
125
136
|
def offering_for(model:, model_family: nil, instance_id: :default, **metadata)
|
|
@@ -140,6 +151,7 @@ module Legion
|
|
|
140
151
|
end
|
|
141
152
|
|
|
142
153
|
def health(live: false)
|
|
154
|
+
log.info { "checking health live=#{live} project=#{project} location=#{location}" }
|
|
143
155
|
baseline = {
|
|
144
156
|
provider: :vertex,
|
|
145
157
|
project: project,
|
|
@@ -154,6 +166,7 @@ module Legion
|
|
|
154
166
|
connection.get(models_url)
|
|
155
167
|
baseline.merge(checked: true)
|
|
156
168
|
rescue StandardError => e
|
|
169
|
+
handle_exception(e, level: :warn, handled: true, operation: 'vertex.provider.health')
|
|
157
170
|
baseline.merge(checked: true, ready: false, error: e.class.name, message: e.message)
|
|
158
171
|
end
|
|
159
172
|
|
|
@@ -166,6 +179,7 @@ module Legion
|
|
|
166
179
|
|
|
167
180
|
def chat(messages, model:, temperature: nil, max_tokens: nil, tools: {}, tool_prefs: nil, params: {})
|
|
168
181
|
model_id = model_id(model)
|
|
182
|
+
log.info { "chat model=#{model_id} messages=#{messages.size}" }
|
|
169
183
|
@model = model_id
|
|
170
184
|
payload = Utils.deep_merge(chat_payload(messages, model: model_id, temperature:, max_tokens:, tools:,
|
|
171
185
|
tool_prefs:, stream: false), params)
|
|
@@ -175,6 +189,7 @@ module Legion
|
|
|
175
189
|
|
|
176
190
|
def stream(messages, model:, temperature: nil, max_tokens: nil, tools: {}, tool_prefs: nil, params: {})
|
|
177
191
|
model_id = model_id(model)
|
|
192
|
+
log.info { "stream model=#{model_id} messages=#{messages.size}" }
|
|
178
193
|
@model = model_id
|
|
179
194
|
payload = Utils.deep_merge(chat_payload(messages, model: model_id, temperature:, max_tokens:, tools:,
|
|
180
195
|
tool_prefs:, stream: true), params)
|
|
@@ -186,6 +201,7 @@ module Legion
|
|
|
186
201
|
|
|
187
202
|
def count_tokens(messages, model:, params: {})
|
|
188
203
|
model_id = model_id(model)
|
|
204
|
+
log.info { "count_tokens model=#{model_id}" }
|
|
189
205
|
unless generate_content_model?(model_id)
|
|
190
206
|
return {
|
|
191
207
|
supported: false,
|
|
@@ -202,6 +218,7 @@ module Legion
|
|
|
202
218
|
|
|
203
219
|
def embed(text, model:, dimensions: nil, task_type: nil, title: nil, params: {})
|
|
204
220
|
model_id = model_id(model)
|
|
221
|
+
log.info { "embed model=#{model_id} inputs=#{Array(text).size}" }
|
|
205
222
|
unless Capabilities.embeddings?(model_id)
|
|
206
223
|
raise NotImplementedError, "Vertex embedding payload for #{model_id} is not standardized"
|
|
207
224
|
end
|
|
@@ -227,6 +244,34 @@ module Legion
|
|
|
227
244
|
|
|
228
245
|
private
|
|
229
246
|
|
|
247
|
+
def model_info_from_static(entry)
|
|
248
|
+
caps = default_capabilities(entry[:model], api: entry.fetch(:api, :generate_content))
|
|
249
|
+
Legion::Extensions::Llm::Model::Info.new(
|
|
250
|
+
id: entry[:model],
|
|
251
|
+
name: entry[:alias] || entry[:model],
|
|
252
|
+
provider: :vertex,
|
|
253
|
+
family: entry[:model_family].to_s,
|
|
254
|
+
capabilities: caps.map(&:to_s),
|
|
255
|
+
metadata: {
|
|
256
|
+
publisher: entry[:publisher],
|
|
257
|
+
project: project,
|
|
258
|
+
location: location,
|
|
259
|
+
api: entry.fetch(:api, :generate_content)
|
|
260
|
+
}.compact
|
|
261
|
+
)
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
def model_info_from_offering(offering)
|
|
265
|
+
Legion::Extensions::Llm::Model::Info.new(
|
|
266
|
+
id: offering.model,
|
|
267
|
+
name: offering.metadata[:alias] || offering.model,
|
|
268
|
+
provider: :vertex,
|
|
269
|
+
family: offering.metadata[:model_family].to_s,
|
|
270
|
+
capabilities: offering.capabilities.map(&:to_s),
|
|
271
|
+
metadata: offering.metadata
|
|
272
|
+
)
|
|
273
|
+
end
|
|
274
|
+
|
|
230
275
|
def static_offerings(**filters)
|
|
231
276
|
STATIC_MODELS.filter_map do |entry|
|
|
232
277
|
next if filters[:model_family] && entry.fetch(:model_family) != filters[:model_family].to_sym
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
require 'legion/extensions/llm'
|
|
4
4
|
require 'legion/extensions/llm/vertex/provider'
|
|
5
|
-
require 'legion/extensions/llm/vertex/registry_event_builder'
|
|
6
|
-
require 'legion/extensions/llm/vertex/registry_publisher'
|
|
7
5
|
require 'legion/extensions/llm/vertex/version'
|
|
8
6
|
|
|
9
7
|
module Legion
|
|
@@ -11,29 +9,23 @@ module Legion
|
|
|
11
9
|
module Llm
|
|
12
10
|
# Google Cloud Vertex AI provider extension namespace.
|
|
13
11
|
module Vertex
|
|
12
|
+
extend Legion::Logging::Helper
|
|
14
13
|
extend ::Legion::Extensions::Core if ::Legion::Extensions.const_defined?(:Core, false)
|
|
15
14
|
|
|
16
15
|
PROVIDER_FAMILY = :vertex
|
|
17
16
|
|
|
18
17
|
def self.default_settings
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
access_token: 'env://VERTEX_ACCESS_TOKEN',
|
|
31
|
-
credentials_file: 'env://GOOGLE_APPLICATION_CREDENTIALS'
|
|
32
|
-
},
|
|
33
|
-
usage: { inference: true, embedding: true, token_counting: true },
|
|
34
|
-
limits: { concurrency: 4 }
|
|
35
|
-
}
|
|
36
|
-
)
|
|
18
|
+
{
|
|
19
|
+
enabled: false,
|
|
20
|
+
default_model: nil,
|
|
21
|
+
project: nil,
|
|
22
|
+
location: 'us-central1',
|
|
23
|
+
model_whitelist: [],
|
|
24
|
+
model_blacklist: [],
|
|
25
|
+
model_cache_ttl: 3600,
|
|
26
|
+
tls: { enabled: false, verify: :peer },
|
|
27
|
+
instances: {}
|
|
28
|
+
}
|
|
37
29
|
end
|
|
38
30
|
|
|
39
31
|
def self.provider_class
|
|
@@ -44,5 +36,6 @@ module Legion
|
|
|
44
36
|
end
|
|
45
37
|
end
|
|
46
38
|
|
|
47
|
-
Legion::Extensions::Llm::
|
|
48
|
-
|
|
39
|
+
Legion::Extensions::Llm::Configuration.register_provider_options(
|
|
40
|
+
Legion::Extensions::Llm::Vertex::Provider.configuration_options
|
|
41
|
+
)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: lex-llm-vertex
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- LegionIO
|
|
@@ -57,14 +57,14 @@ dependencies:
|
|
|
57
57
|
requirements:
|
|
58
58
|
- - ">="
|
|
59
59
|
- !ruby/object:Gem::Version
|
|
60
|
-
version: 0.
|
|
60
|
+
version: 0.2.0
|
|
61
61
|
type: :runtime
|
|
62
62
|
prerelease: false
|
|
63
63
|
version_requirements: !ruby/object:Gem::Requirement
|
|
64
64
|
requirements:
|
|
65
65
|
- - ">="
|
|
66
66
|
- !ruby/object:Gem::Version
|
|
67
|
-
version: 0.
|
|
67
|
+
version: 0.2.0
|
|
68
68
|
description: Google Cloud Vertex AI provider integration for the LegionIO LLM routing
|
|
69
69
|
framework.
|
|
70
70
|
email:
|
|
@@ -85,10 +85,6 @@ files:
|
|
|
85
85
|
- lex-llm-vertex.gemspec
|
|
86
86
|
- lib/legion/extensions/llm/vertex.rb
|
|
87
87
|
- lib/legion/extensions/llm/vertex/provider.rb
|
|
88
|
-
- lib/legion/extensions/llm/vertex/registry_event_builder.rb
|
|
89
|
-
- lib/legion/extensions/llm/vertex/registry_publisher.rb
|
|
90
|
-
- lib/legion/extensions/llm/vertex/transport/exchanges/llm_registry.rb
|
|
91
|
-
- lib/legion/extensions/llm/vertex/transport/messages/registry_event.rb
|
|
92
88
|
- lib/legion/extensions/llm/vertex/version.rb
|
|
93
89
|
homepage: https://github.com/LegionIO/lex-llm-vertex
|
|
94
90
|
licenses:
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Legion
|
|
4
|
-
module Extensions
|
|
5
|
-
module Llm
|
|
6
|
-
module Vertex
|
|
7
|
-
# Builds sanitized lex-llm registry envelopes for Vertex provider state.
|
|
8
|
-
class RegistryEventBuilder
|
|
9
|
-
def readiness(readiness)
|
|
10
|
-
registry_event_class.public_send(
|
|
11
|
-
readiness[:ready] ? :available : :unavailable,
|
|
12
|
-
provider_offering(readiness),
|
|
13
|
-
runtime: runtime_metadata,
|
|
14
|
-
health: readiness_health(readiness),
|
|
15
|
-
metadata: readiness_metadata(readiness)
|
|
16
|
-
)
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def offering_available(offering, readiness:)
|
|
20
|
-
registry_event_class.available(
|
|
21
|
-
offering,
|
|
22
|
-
runtime: runtime_metadata,
|
|
23
|
-
health: offering_health(readiness),
|
|
24
|
-
metadata: offering_metadata
|
|
25
|
-
)
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
private
|
|
29
|
-
|
|
30
|
-
def provider_offering(readiness)
|
|
31
|
-
{
|
|
32
|
-
provider_family: :vertex,
|
|
33
|
-
provider_instance: provider_instance,
|
|
34
|
-
transport: :http,
|
|
35
|
-
model: 'provider-readiness',
|
|
36
|
-
usage_type: :inference,
|
|
37
|
-
capabilities: [],
|
|
38
|
-
health: readiness_health(readiness),
|
|
39
|
-
metadata: { lex: :llm_vertex, provider_readiness: true }
|
|
40
|
-
}
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def readiness_health(readiness)
|
|
44
|
-
health = {
|
|
45
|
-
ready: readiness[:ready] == true,
|
|
46
|
-
status: readiness[:ready] ? :available : :unavailable,
|
|
47
|
-
checked: readiness[:checked] != false
|
|
48
|
-
}
|
|
49
|
-
add_readiness_error(health, readiness)
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def add_readiness_error(health, source)
|
|
53
|
-
error_class = source[:error] || source['error']
|
|
54
|
-
error_message = source[:message] || source['message']
|
|
55
|
-
health[:error_class] = error_class if error_class
|
|
56
|
-
health[:error] = error_message if error_message
|
|
57
|
-
health
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def offering_health(readiness)
|
|
61
|
-
ready = readiness.fetch(:ready, true) == true
|
|
62
|
-
{ ready:, status: ready ? :available : :degraded, checked: readiness[:checked] != false }
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
def readiness_metadata(readiness)
|
|
66
|
-
{
|
|
67
|
-
extension: :lex_llm_vertex,
|
|
68
|
-
provider: :vertex,
|
|
69
|
-
configured: readiness[:configured] == true,
|
|
70
|
-
live: readiness[:live] == true
|
|
71
|
-
}
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
def offering_metadata
|
|
75
|
-
{ extension: :lex_llm_vertex, provider: :vertex }
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
def runtime_metadata
|
|
79
|
-
{ node: provider_instance }
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
def provider_instance
|
|
83
|
-
:vertex
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
def registry_event_class
|
|
87
|
-
::Legion::Extensions::Llm::Routing::RegistryEvent
|
|
88
|
-
end
|
|
89
|
-
end
|
|
90
|
-
end
|
|
91
|
-
end
|
|
92
|
-
end
|
|
93
|
-
end
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Legion
|
|
4
|
-
module Extensions
|
|
5
|
-
module Llm
|
|
6
|
-
module Vertex
|
|
7
|
-
# Best-effort publisher for Vertex provider availability events.
|
|
8
|
-
class RegistryPublisher
|
|
9
|
-
APP_ID = 'lex-llm-vertex'
|
|
10
|
-
|
|
11
|
-
def initialize(builder: RegistryEventBuilder.new)
|
|
12
|
-
@builder = builder
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def publish_readiness_async(readiness)
|
|
16
|
-
schedule { publish_event(@builder.readiness(readiness)) }
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def publish_offerings_async(offerings, readiness:)
|
|
20
|
-
schedule do
|
|
21
|
-
Array(offerings).each do |offering|
|
|
22
|
-
publish_event(@builder.offering_available(offering, readiness:))
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
private
|
|
28
|
-
|
|
29
|
-
def schedule(&)
|
|
30
|
-
return false unless publishing_available?
|
|
31
|
-
|
|
32
|
-
Thread.new do
|
|
33
|
-
Thread.current.abort_on_exception = false
|
|
34
|
-
yield
|
|
35
|
-
rescue StandardError => e
|
|
36
|
-
log_publish_failure(e, level: :debug)
|
|
37
|
-
end
|
|
38
|
-
rescue StandardError => e
|
|
39
|
-
log_publish_failure(e, level: :debug)
|
|
40
|
-
false
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def publish_event(event)
|
|
44
|
-
return false unless publishing_available?
|
|
45
|
-
|
|
46
|
-
message_class.new(event:, app_id: APP_ID).publish(spool: false)
|
|
47
|
-
rescue StandardError => e
|
|
48
|
-
log_publish_failure(e)
|
|
49
|
-
false
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def publishing_available?
|
|
53
|
-
return false unless registry_event_available?
|
|
54
|
-
return false unless transport_message_available?
|
|
55
|
-
return true unless defined?(::Legion::Transport::Connection)
|
|
56
|
-
return true unless ::Legion::Transport::Connection.respond_to?(:session_open?)
|
|
57
|
-
|
|
58
|
-
::Legion::Transport::Connection.session_open?
|
|
59
|
-
rescue StandardError
|
|
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/vertex/transport/messages/registry_event'
|
|
72
|
-
message_class_defined?
|
|
73
|
-
rescue LoadError
|
|
74
|
-
false
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def message_class_defined?
|
|
78
|
-
defined?(::Legion::Extensions::Llm::Vertex::Transport::Messages::RegistryEvent)
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
def message_class
|
|
82
|
-
::Legion::Extensions::Llm::Vertex::Transport::Messages::RegistryEvent
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
def log_publish_failure(error, level: :warn)
|
|
86
|
-
message = "[lex-llm-vertex] llm.registry publish failed: #{error.class}: #{error.message}"
|
|
87
|
-
logger = ::Legion::Extensions::Llm.logger if defined?(::Legion::Extensions::Llm)
|
|
88
|
-
if logger.respond_to?(level)
|
|
89
|
-
logger.public_send(level, message)
|
|
90
|
-
elsif logger.respond_to?(:debug)
|
|
91
|
-
logger.debug(message)
|
|
92
|
-
end
|
|
93
|
-
rescue StandardError
|
|
94
|
-
nil
|
|
95
|
-
end
|
|
96
|
-
end
|
|
97
|
-
end
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
end
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Legion
|
|
4
|
-
module Extensions
|
|
5
|
-
module Llm
|
|
6
|
-
module Vertex
|
|
7
|
-
module Transport
|
|
8
|
-
module Exchanges
|
|
9
|
-
# Topic exchange for Vertex 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
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'legion/extensions/llm/vertex/transport/exchanges/llm_registry'
|
|
4
|
-
|
|
5
|
-
module Legion
|
|
6
|
-
module Extensions
|
|
7
|
-
module Llm
|
|
8
|
-
module Vertex
|
|
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
|