lex-llm-mlx 0.1.7 → 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: b4c018fd3b44a629665783ce38fd5c0f5429ab41452b2e8829079a08c2807860
4
- data.tar.gz: d75bf991619c7d3bf8bc4d7b0aaf77cdb11e6a352595e210ef36f2b6e094cecb
3
+ metadata.gz: 38cb4fb34920395c6af9d7d86f8fbc104c92b632cb886acc601a80815fd64d02
4
+ data.tar.gz: 29ef77ad4cc5ff70720aa9ce298f6d5fbdde58e7dc4836369e4a60bbaf1e70d8
5
5
  SHA512:
6
- metadata.gz: cee424e550ad1ee7cf3a19f791f3bf72434b170efbb50e3e952d5eb502943f442b14ba29344b26575657a390785ad4749ad8d95f7c34454f9d7852160584ff4a
7
- data.tar.gz: 287b5609ee6788ce4865d1b4f1fb49e344198fe5ca1b828f806742810d82d29e1a18fa28c2404b9a8b0144878ea3d52154fb3e702286f02f2a836239f0d7f316
6
+ metadata.gz: c8a71c4d81eaaa3d1aeb66256ae163b922d1ef139317a540fbc62423bbf5d2edc67ca9f9def102420bd9da2d862097ed493dd028a740d58d14ca523f36068ef4
7
+ data.tar.gz: '049f44b3ec25a8ceffa50b6228a7d5a5e20941fa3a54cc142127caa93b075931ad3613ea39dc23bff469fc24c31f5ff5256adc0153a2f53926894403a5c49a34'
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
+
12
+ - Adopt lex-llm 0.1.9 base contract for RegistryPublisher and RegistryEventBuilder.
13
+ - Remove local `RegistryPublisher` and `RegistryEventBuilder` classes in favor of parameterized base versions.
14
+ - Remove local `transport/` directory (exchange and message classes) in favor of shared lex-llm transport layer.
15
+ - Remove deprecated `Provider.register` call; register configuration options directly.
16
+ - Replace `provider_settings` builder with flat `default_settings` hash matching the new consumer contract.
17
+ - Bump gemspec dependency to `lex-llm >= 0.1.9`.
18
+
3
19
  ## 0.1.7 - 2026-04-30
4
20
 
5
21
  - Add `Legion::Logging::Helper` to `Mlx` module and `RegistryPublisher` for standardized logging.
data/lex-llm-mlx.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.1.5'
29
+ spec.add_dependency 'lex-llm', '>= 0.3.0'
30
30
  end
@@ -20,7 +20,7 @@ module Legion
20
20
  def capabilities = Capabilities
21
21
 
22
22
  def registry_publisher
23
- @registry_publisher ||= RegistryPublisher.new
23
+ @registry_publisher ||= Legion::Extensions::Llm::RegistryPublisher.new(provider_family: :mlx)
24
24
  end
25
25
  end
26
26
 
@@ -48,8 +48,12 @@ module Legion
48
48
  end
49
49
  end
50
50
 
51
+ def settings
52
+ Mlx.default_settings
53
+ end
54
+
51
55
  def api_base
52
- config.mlx_api_base || 'http://localhost:8000'
56
+ normalize_url(config.mlx_api_base || 'localhost:8000')
53
57
  end
54
58
 
55
59
  def headers
@@ -4,7 +4,7 @@ module Legion
4
4
  module Extensions
5
5
  module Llm
6
6
  module Mlx
7
- VERSION = '0.1.7'
7
+ VERSION = '0.3.0'
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/mlx/provider'
5
- require 'legion/extensions/llm/mlx/registry_event_builder'
6
- require 'legion/extensions/llm/mlx/registry_publisher'
7
5
  require 'legion/extensions/llm/mlx/version'
8
6
 
9
7
  module Legion
@@ -11,34 +9,64 @@ module Legion
11
9
  module Llm
12
10
  # Mlx provider extension namespace.
13
11
  module Mlx
14
- extend Legion::Logging::Helper if defined?(Legion::Logging::Helper)
12
+ extend Legion::Logging::Helper
15
13
  extend ::Legion::Extensions::Core if ::Legion::Extensions.const_defined?(:Core, false)
14
+ extend Legion::Extensions::Llm::AutoRegistration
16
15
 
17
16
  PROVIDER_FAMILY = :mlx
18
17
 
19
18
  def self.default_settings
20
- ::Legion::Extensions::Llm.provider_settings(
21
- family: PROVIDER_FAMILY,
22
- instance: {
23
- endpoint: 'http://localhost:8000',
24
- tier: :local,
25
- transport: :local,
26
- usage: { inference: true, embedding: true },
27
- limits: { concurrency: 1 }
28
- }
29
- )
19
+ {
20
+ enabled: false,
21
+ base_url: 'localhost:8000',
22
+ default_model: nil,
23
+ api_key: nil,
24
+ model_whitelist: [],
25
+ model_blacklist: [],
26
+ model_cache_ttl: 60,
27
+ tls: { enabled: false, verify: :peer },
28
+ instances: {}
29
+ }
30
30
  end
31
31
 
32
32
  def self.provider_class
33
33
  Provider
34
34
  end
35
+
36
+ def self.discover_instances
37
+ instances = {}
38
+ discover_local_instance(instances)
39
+ discover_settings_instances(instances)
40
+ instances
41
+ end
42
+
43
+ def self.discover_local_instance(instances)
44
+ return unless CredentialSources.socket_open?('localhost', 8080, timeout: 0.1)
45
+
46
+ instances[:local] = {
47
+ base_url: 'http://localhost:8080',
48
+ tier: :local,
49
+ capabilities: [:completion]
50
+ }
51
+ end
52
+
53
+ def self.discover_settings_instances(instances)
54
+ cfg = CredentialSources.setting(:extensions, :llm, :mlx, :instances)
55
+ return unless cfg.is_a?(Hash)
56
+
57
+ cfg.each do |name, config|
58
+ instances[name.to_sym] = config.merge(tier: :direct)
59
+ end
60
+ end
61
+
62
+ private_class_method :discover_local_instance, :discover_settings_instances
35
63
  end
36
64
  end
37
65
  end
38
66
  end
39
67
 
40
- Legion::Extensions::Llm::Provider.register(Legion::Extensions::Llm::Mlx::PROVIDER_FAMILY,
41
- Legion::Extensions::Llm::Mlx::Provider)
42
- if Legion::Extensions::Llm::Mlx.respond_to?(:log)
43
- Legion::Extensions::Llm::Mlx.log.info('Registered MLX provider as :mlx')
44
- end
68
+ Legion::Extensions::Llm::Configuration.register_provider_options(
69
+ Legion::Extensions::Llm::Mlx::Provider.configuration_options
70
+ )
71
+
72
+ Legion::Extensions::Llm::Mlx.register_discovered_instances
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lex-llm-mlx
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
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: MLX 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-mlx.gemspec
85
85
  - lib/legion/extensions/llm/mlx.rb
86
86
  - lib/legion/extensions/llm/mlx/provider.rb
87
- - lib/legion/extensions/llm/mlx/registry_event_builder.rb
88
- - lib/legion/extensions/llm/mlx/registry_publisher.rb
89
- - lib/legion/extensions/llm/mlx/transport/exchanges/llm_registry.rb
90
- - lib/legion/extensions/llm/mlx/transport/messages/registry_event.rb
91
87
  - lib/legion/extensions/llm/mlx/version.rb
92
88
  homepage: https://github.com/LegionIO/lex-llm-mlx
93
89
  licenses:
@@ -1,118 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Legion
4
- module Extensions
5
- module Llm
6
- module Mlx
7
- # Builds sanitized lex-llm registry envelopes for MLX 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 model_available(model, readiness:)
20
- registry_event_class.available(
21
- model_offering(model),
22
- runtime: runtime_metadata,
23
- health: model_health(readiness),
24
- metadata: model_metadata(model)
25
- )
26
- end
27
-
28
- private
29
-
30
- def provider_offering(readiness)
31
- {
32
- provider_family: :mlx,
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_mlx, provider_readiness: true }
40
- }
41
- end
42
-
43
- def model_offering(model)
44
- {
45
- provider_family: :mlx,
46
- provider_instance: provider_instance,
47
- transport: :http,
48
- model: model.id,
49
- usage_type: usage_type_for(model),
50
- capabilities: Array(model.capabilities).map(&:to_sym),
51
- limits: model_limits(model),
52
- metadata: { lex: :llm_mlx, model_name: model.name }.compact
53
- }
54
- end
55
-
56
- def readiness_health(readiness)
57
- health = {
58
- ready: readiness[:ready] == true,
59
- status: readiness[:ready] ? :available : :unavailable,
60
- checked: readiness.dig(:health, :checked) != false
61
- }
62
- add_readiness_error(health, readiness[:health])
63
- end
64
-
65
- def add_readiness_error(health, source)
66
- error = source.is_a?(Hash) ? source : {}
67
- error_class = error[:error] || error['error']
68
- error_message = error[:message] || error['message']
69
- health[:error_class] = error_class if error_class
70
- health[:error] = error_message if error_message
71
- health
72
- end
73
-
74
- def model_health(readiness)
75
- ready = readiness.fetch(:ready, true) == true
76
- { ready:, status: ready ? :available : :degraded }
77
- end
78
-
79
- def readiness_metadata(readiness)
80
- {
81
- extension: :lex_llm_mlx,
82
- provider: :mlx,
83
- configured: readiness[:configured] == true,
84
- live: readiness[:live] == true
85
- }
86
- end
87
-
88
- def model_metadata(model)
89
- { extension: :lex_llm_mlx, provider: :mlx, model_type: model.type }
90
- end
91
-
92
- def runtime_metadata
93
- { node: provider_instance }
94
- end
95
-
96
- def model_limits(model)
97
- {
98
- context_window: model.context_window,
99
- max_output_tokens: model.max_output_tokens
100
- }.compact
101
- end
102
-
103
- def usage_type_for(model)
104
- model.type == 'embedding' ? :embedding : :inference
105
- end
106
-
107
- def provider_instance
108
- :mlx
109
- end
110
-
111
- def registry_event_class
112
- ::Legion::Extensions::Llm::Routing::RegistryEvent
113
- end
114
- end
115
- end
116
- end
117
- end
118
- end
@@ -1,97 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Legion
4
- module Extensions
5
- module Llm
6
- module Mlx
7
- # Best-effort publisher for MLX provider availability events.
8
- class RegistryPublisher
9
- include Legion::Logging::Helper if defined?(Legion::Logging::Helper)
10
-
11
- APP_ID = 'lex-llm-mlx'
12
-
13
- def initialize(builder: RegistryEventBuilder.new)
14
- @builder = builder
15
- end
16
-
17
- def publish_readiness_async(readiness)
18
- log.info('Publishing MLX readiness event asynchronously')
19
- schedule { publish_event(@builder.readiness(readiness)) }
20
- end
21
-
22
- def publish_models_async(models, readiness:)
23
- log.info("Publishing #{Array(models).size} MLX model availability events asynchronously")
24
- schedule do
25
- Array(models).each do |model|
26
- publish_event(@builder.model_available(model, readiness:))
27
- end
28
- end
29
- end
30
-
31
- private
32
-
33
- def schedule(&)
34
- return false unless publishing_available?
35
-
36
- Thread.new do
37
- Thread.current.abort_on_exception = false
38
- yield
39
- rescue StandardError => e
40
- handle_exception(e, level: :debug, handled: true, operation: 'mlx.registry_publisher.schedule_thread')
41
- end
42
- rescue StandardError => e
43
- handle_exception(e, level: :debug, handled: true, operation: 'mlx.registry_publisher.schedule')
44
- false
45
- end
46
-
47
- def publish_event(event)
48
- return false unless publishing_available?
49
-
50
- log.info("Publishing MLX registry event: #{event.class}")
51
- message_class.new(event:, app_id: APP_ID).publish(spool: false)
52
- rescue StandardError => e
53
- handle_exception(e, level: :warn, handled: true, operation: 'mlx.registry_publisher.publish_event')
54
- false
55
- end
56
-
57
- def publishing_available?
58
- return false unless registry_event_available?
59
- return false unless transport_message_available?
60
- return true unless defined?(::Legion::Transport::Connection)
61
- return true unless ::Legion::Transport::Connection.respond_to?(:session_open?)
62
-
63
- ::Legion::Transport::Connection.session_open?
64
- rescue StandardError => e
65
- handle_exception(e, level: :debug, handled: true,
66
- operation: 'mlx.registry_publisher.publishing_available?')
67
- false
68
- end
69
-
70
- def registry_event_available?
71
- defined?(::Legion::Extensions::Llm::Routing::RegistryEvent)
72
- end
73
-
74
- def transport_message_available?
75
- return true if message_class_defined?
76
- return false unless defined?(::Legion::Transport::Message) && defined?(::Legion::Transport::Exchange)
77
-
78
- require 'legion/extensions/llm/mlx/transport/messages/registry_event'
79
- message_class_defined?
80
- rescue LoadError => e
81
- handle_exception(e, level: :debug, handled: true,
82
- operation: 'mlx.registry_publisher.transport_message_available?')
83
- false
84
- end
85
-
86
- def message_class_defined?
87
- defined?(::Legion::Extensions::Llm::Mlx::Transport::Messages::RegistryEvent)
88
- end
89
-
90
- def message_class
91
- ::Legion::Extensions::Llm::Mlx::Transport::Messages::RegistryEvent
92
- end
93
- end
94
- end
95
- end
96
- end
97
- end
@@ -1,24 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Legion
4
- module Extensions
5
- module Llm
6
- module Mlx
7
- module Transport
8
- module Exchanges
9
- # Topic exchange for MLX 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/mlx/transport/exchanges/llm_registry'
4
-
5
- module Legion
6
- module Extensions
7
- module Llm
8
- module Mlx
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