lex-llm-openai 0.1.8 → 0.3.0

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: 923d77b5cf761e20eccb817d66dd36bec5310842f1216c2b403432bf84bf11fa
4
- data.tar.gz: e84b863710db389adf98f1b06783c46e4e4b7797c51889026c62939a3e3ad9a6
3
+ metadata.gz: 3cd48c5acd857910771717afe92892f537270d62a6f6d24d0f71e2b5805abb9d
4
+ data.tar.gz: c8f1a0644cb7cf1fe993f6d17b5aba3167e56d8f44f04fe0e0d6afe8d70a7146
5
5
  SHA512:
6
- metadata.gz: 3ea2f8c543f3e8cbdf55a158bb0033d1711b34b3114ea8ebbccc530d398ac3931e95d3c729be869eac5070dac773edec62e3de1dc94b3c00a4560c6b6a998cbe
7
- data.tar.gz: 5672bc7469d4a09a12c85fcd343c8008748ccb6a90f85dc54cfdf7feb9d81721a026aa91a11d555b826159fbe61a528732301cf19ab63470800068faa1971a42
6
+ metadata.gz: 2f5a9d6f495bb5fac304ef891d5f2f93353ff0d6909c54c506a448030e67791f7b79fbffb546e8b7cf94b5d8d8eef1f4b8122bd5df7115e47ff537baa33e8483
7
+ data.tar.gz: 7f40adfce35ab368b2db2d82a603fe48f2de269e13a093cab8adc15a946b80e2d02792fd97cf400895f55a18529f140d630e7dd4264d1f0799aa3328dd71908d
data/.rubocop.yml CHANGED
@@ -12,7 +12,11 @@ Metrics/BlockLength:
12
12
  Exclude:
13
13
  - "*.gemspec"
14
14
  - spec/**/*
15
+ Metrics/ClassLength:
16
+ Max: 200
15
17
  Metrics/MethodLength:
16
18
  Enabled: false
19
+ RSpec/ExampleLength:
20
+ Max: 10
17
21
  RSpec/MultipleExpectations:
18
22
  Enabled: false
data/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.0 - 2026-05-01
4
+
5
+ - Add auto-discovery via CredentialSources and AutoRegistration from lex-llm 0.3.0
6
+ - Self-register discovered instances into Call::Registry at require-time
7
+ - Require lex-llm >= 0.3.0
8
+
9
+
10
+ ## [0.2.0] - 2026-04-30
11
+ - **BREAKING**: Adopt base contract from lex-llm 0.1.9; require `lex-llm >= 0.1.9`
12
+ - Replace `provider_settings`-based `default_settings` with flat provider defaults (enabled, default_model, api_key, etc.)
13
+ - Remove deprecated `Provider.register` call; configuration options are now registered at class-load time
14
+ - Delete local `RegistryPublisher` and `RegistryEventBuilder`; use parameterized base classes from lex-llm
15
+ - Delete local `transport/` directory (exchanges, messages); use shared transport from lex-llm
16
+ - Add static `CAPABILITY_MAP` for known OpenAI model families; `list_models` now returns `Model::Info` structs directly
17
+ - `list_models` no longer delegates to `parse_list_models_response`; builds `Model::Info` via the static capability map
18
+
3
19
  ## [0.1.8] - 2026-04-30
4
20
  - Add Legion::Logging::Helper to all modules and classes for structured observability
5
21
  - Replace bare rescue blocks with handle_exception for unified error telemetry
@@ -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.3.0'
30
30
  end
@@ -9,7 +9,84 @@ module Legion
9
9
  # OpenAI provider implementation for the Legion::Extensions::Llm base provider contract.
10
10
  class Provider < Legion::Extensions::Llm::Provider
11
11
  include Legion::Extensions::Llm::Provider::OpenAICompatible
12
- include Legion::Logging::Helper if defined?(Legion::Logging::Helper)
12
+ include Legion::Logging::Helper
13
+
14
+ # ── Static capability map for known OpenAI model families ──────
15
+ # Maps model-id prefixes to a set of capabilities and modality
16
+ # vectors. Used by list_models to build Model::Info structs from
17
+ # the raw /v1/models response.
18
+ CAPABILITY_MAP = {
19
+ 'gpt-4o' => {
20
+ capabilities: %i[completion streaming function_calling vision structured_output],
21
+ modalities_input: %w[text image audio],
22
+ modalities_output: %w[text]
23
+ },
24
+ 'gpt-4.1' => {
25
+ capabilities: %i[completion streaming function_calling vision structured_output],
26
+ modalities_input: %w[text image],
27
+ modalities_output: %w[text]
28
+ },
29
+ 'gpt-4' => {
30
+ capabilities: %i[completion streaming function_calling vision],
31
+ modalities_input: %w[text image],
32
+ modalities_output: %w[text]
33
+ },
34
+ 'gpt-5' => {
35
+ capabilities: %i[completion streaming function_calling vision structured_output reasoning],
36
+ modalities_input: %w[text image],
37
+ modalities_output: %w[text]
38
+ },
39
+ 'o4' => {
40
+ capabilities: %i[completion streaming function_calling vision reasoning],
41
+ modalities_input: %w[text image],
42
+ modalities_output: %w[text]
43
+ },
44
+ 'o3' => {
45
+ capabilities: %i[completion streaming function_calling vision reasoning],
46
+ modalities_input: %w[text image],
47
+ modalities_output: %w[text]
48
+ },
49
+ 'o1' => {
50
+ capabilities: %i[completion streaming function_calling vision reasoning],
51
+ modalities_input: %w[text image],
52
+ modalities_output: %w[text]
53
+ },
54
+ 'text-embedding-' => {
55
+ capabilities: %i[embedding],
56
+ modalities_input: %w[text],
57
+ modalities_output: %w[embeddings]
58
+ },
59
+ 'omni-moderation' => {
60
+ capabilities: %i[moderation],
61
+ modalities_input: %w[text image],
62
+ modalities_output: %w[moderation]
63
+ },
64
+ 'text-moderation' => {
65
+ capabilities: %i[moderation],
66
+ modalities_input: %w[text],
67
+ modalities_output: %w[moderation]
68
+ },
69
+ 'gpt-image' => {
70
+ capabilities: %i[image_generation],
71
+ modalities_input: %w[text image],
72
+ modalities_output: %w[image]
73
+ },
74
+ 'dall-e' => {
75
+ capabilities: %i[image_generation],
76
+ modalities_input: %w[text],
77
+ modalities_output: %w[image]
78
+ },
79
+ 'whisper' => {
80
+ capabilities: %i[audio_transcription],
81
+ modalities_input: %w[audio],
82
+ modalities_output: %w[text]
83
+ },
84
+ 'tts' => {
85
+ capabilities: %i[audio_generation],
86
+ modalities_input: %w[text],
87
+ modalities_output: %w[audio]
88
+ }
89
+ }.freeze
13
90
 
14
91
  class << self
15
92
  attr_writer :registry_publisher
@@ -30,7 +107,7 @@ module Legion
30
107
  def capabilities = Capabilities
31
108
 
32
109
  def registry_publisher
33
- @registry_publisher ||= RegistryPublisher.new
110
+ @registry_publisher ||= Legion::Extensions::Llm::RegistryPublisher.new(provider_family: :openai)
34
111
  end
35
112
  end
36
113
 
@@ -95,32 +172,66 @@ module Legion
95
172
  def images_url(with: nil, mask: nil) = super
96
173
 
97
174
  def retrieve_model(model)
98
- log.info("Retrieving model: #{model}") if respond_to?(:log)
175
+ log.info("Retrieving model: #{model}")
99
176
  connection.get("#{models_url}/#{model}").body
100
177
  rescue StandardError => e
101
- if respond_to?(:handle_exception)
102
- handle_exception(e, level: :error, handled: true,
103
- operation: 'retrieve_model')
104
- end
178
+ handle_exception(e, level: :error, handled: true,
179
+ operation: 'retrieve_model')
105
180
  raise
106
181
  end
107
182
 
108
183
  def list_models
109
- log.info('Listing OpenAI models') if respond_to?(:log)
110
- super.tap do |models|
111
- log.info("Discovered #{models.size} OpenAI models") if respond_to?(:log)
112
- self.class.registry_publisher.publish_models_async(models, readiness: readiness(live: false))
113
- end
184
+ log.info('Listing OpenAI models')
185
+ raw = connection.get(models_url)
186
+ models = build_model_infos(raw.body)
187
+ log.info("Discovered #{models.size} OpenAI models")
188
+ self.class.registry_publisher.publish_models_async(models, readiness: readiness(live: false))
189
+ models
114
190
  rescue StandardError => e
115
- if respond_to?(:handle_exception)
116
- handle_exception(e, level: :error, handled: true,
117
- operation: 'list_models')
118
- end
191
+ handle_exception(e, level: :error, handled: true,
192
+ operation: 'list_models')
119
193
  raise
120
194
  end
121
195
 
122
196
  private
123
197
 
198
+ def build_model_infos(body)
199
+ body.fetch('data', []).map do |raw_model|
200
+ id = raw_model.fetch('id')
201
+ cap_entry = capability_entry_for(id)
202
+
203
+ Legion::Extensions::Llm::Model::Info.new(
204
+ id: id,
205
+ name: id,
206
+ provider: :openai,
207
+ capabilities: cap_entry[:capabilities],
208
+ modalities_input: cap_entry[:modalities_input],
209
+ modalities_output: cap_entry[:modalities_output],
210
+ metadata: {
211
+ created_at: model_created_at(raw_model['created']),
212
+ raw: raw_model
213
+ }.compact
214
+ )
215
+ end
216
+ end
217
+
218
+ def capability_entry_for(model_id)
219
+ CAPABILITY_MAP.each do |prefix, entry|
220
+ return entry if model_id.start_with?(prefix)
221
+ end
222
+
223
+ # Fallback for unknown models: assume chat-capable
224
+ {
225
+ capabilities: %i[completion streaming],
226
+ modalities_input: %w[text],
227
+ modalities_output: %w[text]
228
+ }
229
+ end
230
+
231
+ def model_created_at(value)
232
+ value.is_a?(Numeric) ? Time.at(value).utc : value
233
+ end
234
+
124
235
  def maybe_normalize_temperature(temperature, model)
125
236
  model_id = model.id.to_s
126
237
  return nil if model_id.include?('-search')
@@ -133,3 +244,10 @@ module Legion
133
244
  end
134
245
  end
135
246
  end
247
+
248
+ # Register configuration options so Legion::Extensions::Llm::Configuration knows about them.
249
+ if Legion::Extensions::Llm::Configuration.respond_to?(:register_provider_options)
250
+ Legion::Extensions::Llm::Configuration.register_provider_options(
251
+ Legion::Extensions::Llm::Openai::Provider.configuration_options
252
+ )
253
+ end
@@ -4,7 +4,7 @@ module Legion
4
4
  module Extensions
5
5
  module Llm
6
6
  module Openai
7
- VERSION = '0.1.8'
7
+ VERSION = '0.3.0'
8
8
  end
9
9
  end
10
10
  end
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'legion/extensions/llm'
4
- require 'legion/extensions/llm/openai/registry_event_builder'
5
- require 'legion/extensions/llm/openai/registry_publisher'
6
4
  require 'legion/extensions/llm/openai/provider'
7
5
  require 'legion/extensions/llm/openai/version'
8
6
 
@@ -12,34 +10,81 @@ module Legion
12
10
  # Openai provider extension namespace.
13
11
  module Openai
14
12
  extend ::Legion::Extensions::Core if ::Legion::Extensions.const_defined?(:Core, false)
15
- extend ::Legion::Logging::Helper if defined?(::Legion::Logging::Helper)
13
+ extend ::Legion::Logging::Helper
14
+ extend Legion::Extensions::Llm::AutoRegistration
16
15
 
17
16
  PROVIDER_FAMILY = :openai
18
17
 
19
18
  def self.default_settings
20
- ::Legion::Extensions::Llm.provider_settings(
21
- family: PROVIDER_FAMILY,
22
- instance: {
23
- endpoint: 'https://api.openai.com',
24
- tier: :frontier,
25
- transport: :http,
26
- credentials: { api_key: 'env://OPENAI_API_KEY' },
27
- usage: { inference: true, embedding: true, moderation: true, image: true, audio: true },
28
- limits: { concurrency: 4 }
29
- }
30
- )
19
+ {
20
+ enabled: false,
21
+ default_model: 'gpt-4o',
22
+ api_key: nil,
23
+ organization_id: nil,
24
+ project_id: nil,
25
+ model_whitelist: [],
26
+ model_blacklist: [],
27
+ model_cache_ttl: 3600,
28
+ tls: { enabled: false, verify: :peer },
29
+ instances: {}
30
+ }
31
31
  end
32
32
 
33
33
  def self.provider_class
34
34
  Provider
35
35
  end
36
+
37
+ def self.discover_instances # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
38
+ candidates = {}
39
+
40
+ # 1. OPENAI_API_KEY environment variable
41
+ env_key = CredentialSources.env('OPENAI_API_KEY')
42
+ candidates[:env] = { openai_api_key: env_key, tier: :frontier } if env_key
43
+
44
+ # 2. CODEX_API_KEY environment variable
45
+ codex_env_key = CredentialSources.env('CODEX_API_KEY')
46
+ candidates[:codex_env] = { openai_api_key: codex_env_key, tier: :frontier } if codex_env_key
47
+
48
+ # 3. Codex bearer token (~/.codex/auth.json chatgpt mode)
49
+ codex_tok = CredentialSources.codex_token
50
+ candidates[:codex] = { openai_api_key: codex_tok, tier: :frontier } if codex_tok
51
+
52
+ # 4. Codex OPENAI_API_KEY from ~/.codex/auth.json
53
+ codex_key = CredentialSources.codex_openai_key
54
+ candidates[:codex_key] = { openai_api_key: codex_key, tier: :frontier } if codex_key
55
+
56
+ # 5. Claude config openaiApiKey
57
+ claude_key = CredentialSources.claude_config_value(:openaiApiKey)
58
+ candidates[:claude] = { openai_api_key: claude_key, tier: :frontier } if claude_key
59
+
60
+ # 6. Extension settings
61
+ settings_config = CredentialSources.setting(:extensions, :llm, :openai)
62
+ if settings_config.is_a?(Hash) && !settings_config.empty?
63
+ settings_key = settings_config[:api_key] || settings_config['api_key']
64
+ if settings_key
65
+ candidates[:settings] = settings_config.merge(
66
+ openai_api_key: settings_key,
67
+ tier: :frontier
68
+ )
69
+ end
70
+ end
71
+
72
+ # 7. Gateway instances from extension settings
73
+ gateways = CredentialSources.setting(:extensions, :llm, :openai, :gateways)
74
+ if gateways.is_a?(Hash)
75
+ gateways.each do |name, config|
76
+ next unless config.is_a?(Hash)
77
+
78
+ candidates[name.to_sym] = config.merge(tier: :openai_compat)
79
+ end
80
+ end
81
+
82
+ # 8. Dedup
83
+ CredentialSources.dedup_credentials(candidates)
84
+ end
36
85
  end
37
86
  end
38
87
  end
39
88
  end
40
89
 
41
- Legion::Extensions::Llm::Provider.register(Legion::Extensions::Llm::Openai::PROVIDER_FAMILY,
42
- Legion::Extensions::Llm::Openai::Provider)
43
- if defined?(Legion::Logging::Helper) && Legion::Extensions::Llm::Openai.respond_to?(:log)
44
- Legion::Extensions::Llm::Openai.log.info('Registered OpenAI provider for :openai family')
45
- end
90
+ Legion::Extensions::Llm::Openai.register_discovered_instances
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lex-llm-openai
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.8
4
+ version: 0.3.0
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.3.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.3.0
68
68
  description: OpenAI provider integration for the LegionIO LLM routing framework.
69
69
  email:
70
70
  - matthewdiverson@gmail.com
@@ -84,10 +84,6 @@ files:
84
84
  - lex-llm-openai.gemspec
85
85
  - lib/legion/extensions/llm/openai.rb
86
86
  - lib/legion/extensions/llm/openai/provider.rb
87
- - lib/legion/extensions/llm/openai/registry_event_builder.rb
88
- - lib/legion/extensions/llm/openai/registry_publisher.rb
89
- - lib/legion/extensions/llm/openai/transport/exchanges/llm_registry.rb
90
- - lib/legion/extensions/llm/openai/transport/messages/registry_event.rb
91
87
  - lib/legion/extensions/llm/openai/version.rb
92
88
  homepage: https://github.com/LegionIO/lex-llm-openai
93
89
  licenses:
@@ -1,78 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Legion
4
- module Extensions
5
- module Llm
6
- module Openai
7
- # Builds sanitized lex-llm registry envelopes for OpenAI 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: :openai,
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_openai, 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_openai, provider: :openai, 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? ? :openai : value.to_sym
63
- rescue StandardError => e
64
- if respond_to?(:handle_exception)
65
- handle_exception(e, level: :debug, handled: true,
66
- operation: 'provider_instance')
67
- end
68
- :openai
69
- end
70
-
71
- def registry_event_class
72
- ::Legion::Extensions::Llm::Routing::RegistryEvent
73
- end
74
- end
75
- end
76
- end
77
- end
78
- end
@@ -1,98 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Legion
4
- module Extensions
5
- module Llm
6
- module Openai
7
- # Best-effort publisher for OpenAI provider availability events.
8
- class RegistryPublisher
9
- include Legion::Logging::Helper if defined?(Legion::Logging::Helper)
10
-
11
- APP_ID = 'lex-llm-openai'
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(s) to llm.registry") if respond_to?(:log)
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: 'schedule') if respond_to?(:handle_exception)
36
- end
37
- rescue StandardError => e
38
- handle_exception(e, level: :debug, handled: true, operation: 'schedule') if respond_to?(:handle_exception)
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
- if respond_to?(:handle_exception)
48
- handle_exception(e, level: :warn, handled: true,
49
- operation: 'publish_event')
50
- end
51
- false
52
- end
53
-
54
- def publishing_available?
55
- return false unless registry_event_available?
56
- return false unless transport_message_available?
57
- return true unless defined?(::Legion::Transport::Connection)
58
- return true unless ::Legion::Transport::Connection.respond_to?(:session_open?)
59
-
60
- ::Legion::Transport::Connection.session_open?
61
- rescue StandardError => e
62
- if respond_to?(:handle_exception)
63
- handle_exception(e, level: :debug, handled: true,
64
- operation: 'publishing_available?')
65
- end
66
- false
67
- end
68
-
69
- def registry_event_available?
70
- defined?(::Legion::Extensions::Llm::Routing::RegistryEvent)
71
- end
72
-
73
- def transport_message_available?
74
- return true if message_class_defined?
75
- return false unless defined?(::Legion::Transport::Message) && defined?(::Legion::Transport::Exchange)
76
-
77
- require 'legion/extensions/llm/openai/transport/messages/registry_event'
78
- message_class_defined?
79
- rescue LoadError => e
80
- if respond_to?(:handle_exception)
81
- handle_exception(e, level: :debug, handled: true,
82
- operation: 'transport_message_available?')
83
- end
84
- false
85
- end
86
-
87
- def message_class_defined?
88
- defined?(::Legion::Extensions::Llm::Openai::Transport::Messages::RegistryEvent)
89
- end
90
-
91
- def message_class
92
- ::Legion::Extensions::Llm::Openai::Transport::Messages::RegistryEvent
93
- end
94
- end
95
- end
96
- end
97
- end
98
- end
@@ -1,24 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Legion
4
- module Extensions
5
- module Llm
6
- module Openai
7
- module Transport
8
- module Exchanges
9
- # Topic exchange for OpenAI 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/openai/transport/exchanges/llm_registry'
4
-
5
- module Legion
6
- module Extensions
7
- module Llm
8
- module Openai
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