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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aea77e247a75b2b4864b832da66786008115bc64861fd1ec06a57978456508b0
4
- data.tar.gz: 6082e13d0afe17cd77291494c4041a7ad0a0aae1d9fc19fb539edd398f9bea01
3
+ metadata.gz: 524d4e5a1420c6a145c89da553e021205e5447c462509b4397161b01d8c37ed6
4
+ data.tar.gz: 4b6afd972ba22dacbcfd844287ee8828bfefa05cdce2a13ec2ff052f7fdb28b0
5
5
  SHA512:
6
- metadata.gz: '003679cd2e49ab95aec1664309ea6ee28ba08ddc7464ab5ea4e26618550ea19ae6c2b732df89097abe378197a17c6bacc48234a6b1f4658f514b1de6decab301'
7
- data.tar.gz: 8665225fa69d9c1178a456160e1e50ba52854d42b660ebcaf92a3d3c9c1d683433f754ddcd061dcf98e7f36d4cdc353a8b9a3f0a55142027874e761cafff195f
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
- Google Cloud references:
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)
@@ -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.1.5'
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) }.tap do |offerings|
121
- self.class.registry_publisher.publish_offerings_async(offerings, readiness: readiness(live: false))
122
- end
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
@@ -4,7 +4,7 @@ module Legion
4
4
  module Extensions
5
5
  module Llm
6
6
  module Vertex
7
- VERSION = '0.1.4'
7
+ VERSION = '0.1.6'
8
8
  end
9
9
  end
10
10
  end
@@ -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
- ::Legion::Extensions::Llm.provider_settings(
20
- family: PROVIDER_FAMILY,
21
- discovery: { enabled: true, live: false, locations: %w[us-central1 us-east5 europe-west4] },
22
- instance: {
23
- endpoint: 'https://us-central1-aiplatform.googleapis.com/v1',
24
- project: 'env://GOOGLE_CLOUD_PROJECT',
25
- location: 'us-central1',
26
- tier: :frontier,
27
- transport: :http,
28
- credentials: {
29
- provider: 'google-application-default-credentials',
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::Provider.register(Legion::Extensions::Llm::Vertex::PROVIDER_FAMILY,
48
- Legion::Extensions::Llm::Vertex::Provider)
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
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.1.5
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.1.5
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