lex-llm-mlx 0.3.13 → 0.5.2

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.
@@ -20,14 +20,19 @@ module Legion
20
20
  module Actor
21
21
  # Subscription actor for MLX fleet request consumption.
22
22
  class FleetWorker < Legion::Extensions::Actors::Subscription
23
+ # The runner module as a constant: the Subscription dispatch
24
+ # path calls `runner_class.send(runner_function, **message)`,
25
+ # which a String cannot receive.
23
26
  def runner_class
24
- 'Legion::Extensions::Llm::Mlx::Runners::FleetWorker'
27
+ Legion::Extensions::Llm::Mlx::Runners::FleetWorker
25
28
  end
26
29
 
27
30
  def runner_function
28
31
  'handle_fleet_request'
29
32
  end
30
33
 
34
+ # Call the runner module directly — no task record per
35
+ # inference hop.
31
36
  def use_runner?
32
37
  false
33
38
  end
@@ -6,119 +6,113 @@ module Legion
6
6
  module Extensions
7
7
  module Llm
8
8
  module Mlx
9
- # MLX provider implementation for local OpenAI-compatible servers.
10
- class Provider < Legion::Extensions::Llm::Provider # rubocop:disable Metrics/ClassLength
11
- include Legion::Extensions::Llm::Provider::OpenAICompatible
12
-
13
- class << self
14
- attr_writer :registry_publisher
15
-
16
- def slug = 'mlx'
17
- def local? = true
18
- def default_transport = :http
19
- def default_tier = :local
20
- def configuration_options = %i[mlx_api_base mlx_api_key]
21
- def configuration_requirements = []
22
- def capabilities = Capabilities
9
+ # Conservative capability predicates for local MLX OpenAI-compatible servers.
10
+ module Capabilities
11
+ module_function
12
+
13
+ def chat?(model) = !embeddings?(model)
14
+ def streaming?(model) = chat?(model)
15
+ def vision?(model) = model_id(model).match?(/vlm|vision|llava|pixtral|qwen.*vl/i)
16
+ def functions?(model) = chat?(model)
17
+ def embeddings?(model) = model_id(model).match?(/embed|bge|e5|nomic/i)
18
+
19
+ def critical_capabilities_for(model)
20
+ [
21
+ ('streaming' if streaming?(model)),
22
+ ('function_calling' if functions?(model)),
23
+ ('vision' if vision?(model)),
24
+ ('embeddings' if embeddings?(model))
25
+ ].compact
26
+ end
23
27
 
24
- def registry_publisher
25
- @registry_publisher ||= Legion::Extensions::Llm::RegistryPublisher.new(provider_family: :mlx)
26
- end
28
+ def model_id(model)
29
+ model.respond_to?(:id) ? model.id.to_s : model.to_s
27
30
  end
31
+ end
28
32
 
29
- # Conservative capability predicates for local MLX OpenAI-compatible servers.
30
- module Capabilities
31
- module_function
33
+ # Capability config helpers mix into Provider.
34
+ module CapabilityConfig
35
+ private
32
36
 
33
- def chat?(model) = !embeddings?(model)
34
- def streaming?(model) = chat?(model)
35
- def vision?(model) = model_id(model).match?(/vlm|vision|llava|pixtral|qwen.*vl/i)
36
- def functions?(model) = chat?(model)
37
- def embeddings?(model) = model_id(model).match?(/embed|bge|e5|nomic/i)
37
+ def provider_capability_config
38
+ conf = Legion::Extensions::Llm::CredentialSources.setting(:extensions, :llm, :mlx)
39
+ conf.is_a?(Hash) ? conf.to_h.except(:instances, 'instances') : {}
40
+ rescue StandardError => e
41
+ handle_exception(e, level: :warn, handled: true, operation: 'mlx.provider_capability_config')
42
+ {}
43
+ end
38
44
 
39
- def critical_capabilities_for(model)
40
- [
41
- ('streaming' if streaming?(model)),
42
- ('function_calling' if functions?(model)),
43
- ('vision' if vision?(model)),
44
- ('embeddings' if embeddings?(model))
45
- ].compact
46
- end
45
+ def instance_capability_config
46
+ cfg = config
47
+ result = {}
48
+ %i[capabilities enable_thinking enable_tools enable_streaming enable_vision enable_embeddings
49
+ thinking_flag tools_flag streaming_flag vision_flag embedding_flag embeddings_flag
50
+ tool_flag images_flag image_flag].each do |key|
51
+ next unless cfg.respond_to?(key)
47
52
 
48
- def model_id(model)
49
- model.respond_to?(:id) ? model.id.to_s : model.to_s
53
+ val = cfg.send(key)
54
+ result[key] = val unless val.nil?
55
+ rescue StandardError => e
56
+ handle_exception(e, level: :warn, handled: true, operation: 'mlx.provider.instance_capability_config')
57
+ next
50
58
  end
59
+ result
51
60
  end
52
61
 
53
- def settings
54
- Mlx.default_settings
55
- end
62
+ def model_capability_config(model_id)
63
+ models_conf = fetch_models_config
64
+ return {} unless models_conf
56
65
 
57
- def api_base
58
- normalize_url(config.mlx_api_base || settings[:endpoint] || 'http://localhost:8000')
66
+ hash = models_conf.to_h
67
+ hash[model_id.to_s] || hash[model_id.to_sym] || {}
68
+ rescue StandardError => e
69
+ handle_exception(e, level: :warn, handled: true, operation: 'mlx.model_capability_config')
70
+ {}
59
71
  end
60
72
 
61
- def headers
62
- hdrs = identity_headers
63
- token = config.mlx_api_key
64
- hdrs['Authorization'] = "Bearer #{token}" unless token.nil? || token.to_s.empty?
65
- hdrs
73
+ def fetch_models_config
74
+ conf = config.models if config.respond_to?(:models)
75
+ conf ||= config[:models] if config.respond_to?(:[])
76
+ conf if conf.respond_to?(:to_h)
77
+ rescue StandardError => e
78
+ handle_exception(e, level: :warn, handled: true, operation: 'mlx.fetch_models_config')
79
+ nil
66
80
  end
81
+ end
67
82
 
68
- def health_url = '/health'
83
+ # Health payload helpers — mix into Provider.
84
+ module HealthHelpers
85
+ private
69
86
 
70
- def health(live: false)
71
- log.info("Checking MLX health live=#{live} at #{api_base}#{health_url}")
72
- raw = connection.get(health_url).body
73
- health_payload(raw)
74
- rescue StandardError => e
75
- handle_exception(e, level: :warn, handled: true, operation: 'mlx.provider.health')
87
+ def health_payload(raw)
88
+ ready = health_ready?(raw)
89
+ status = health_status(ready)
76
90
  {
77
91
  provider: :mlx,
78
92
  instance_id: provider_instance_id,
79
- status: 'unhealthy',
80
- ready: false,
81
- circuit_state: 'open',
82
- error: e.class.name,
83
- message: e.message
93
+ status: status,
94
+ ready: ready,
95
+ circuit_state: circuit_state(status),
96
+ raw: raw
84
97
  }
85
98
  end
86
99
 
87
- def readiness(live: false)
88
- log.info("Checking MLX readiness (live=#{live})")
89
- super.tap do |metadata|
90
- self.class.registry_publisher.publish_readiness_async(metadata) if live
91
- end
100
+ def health_ready?(raw)
101
+ raw.is_a?(Hash) ? raw.fetch('ready', raw.fetch(:ready, true)) : true
92
102
  end
93
103
 
94
- def list_models(**)
95
- log.info('Listing available MLX models')
96
- super.tap do |models|
97
- log.info("Discovered #{Array(models).size} MLX models")
98
- self.class.registry_publisher.publish_models_async(models, readiness: readiness(live: false))
99
- end
104
+ def health_status(ready)
105
+ ready ? 'healthy' : 'unhealthy'
100
106
  end
101
107
 
102
- def offering_from_model(model_info, health: {}) # rubocop:disable Metrics/AbcSize
103
- policy = resolve_capability_policy(model_info)
104
- ctx = model_info.respond_to?(:context_length) ? model_info.context_length : nil
105
-
106
- Legion::Extensions::Llm::Routing::ModelOffering.new(
107
- provider_family: :mlx,
108
- instance_id: config.respond_to?(:instance_id) ? config.instance_id : :default,
109
- transport: offering_transport,
110
- tier: offering_tier,
111
- model: model_info.id,
112
- canonical_model_alias: model_info.respond_to?(:name) ? model_info.name : nil,
113
- model_family: model_info.respond_to?(:family) ? model_info.family : nil,
114
- usage_type: embedding_model?(model_info.id) ? :embedding : :inference,
115
- capabilities: policy[:capabilities],
116
- capability_sources: policy[:sources],
117
- limits: { context_window: ctx }.compact,
118
- health: health,
119
- metadata: offering_metadata_for(model_info).merge(capability_sources: policy[:sources])
120
- )
108
+ def circuit_state(status)
109
+ status == 'healthy' ? 'closed' : 'open'
121
110
  end
111
+ end
112
+
113
+ # Capability resolution helpers — mix into Provider.
114
+ module CapabilityResolution
115
+ private
122
116
 
123
117
  def resolve_capability_policy(model_info)
124
118
  Legion::Extensions::Llm::CapabilityPolicy.resolve(
@@ -142,13 +136,10 @@ module Legion
142
136
  caps.is_a?(Hash) ? caps : {}
143
137
  end
144
138
 
145
- def extract_catalog_capabilities(model_info)
146
- model_id = model_info.respond_to?(:id) ? model_info.id.to_s : model_info.to_s
147
- caps = {}
148
- caps[:embeddings] = true if model_id.match?(/embed|bge|e5|nomic/i)
149
- caps[:vision] = true if model_id.match?(/vlm|vision|llava|pixtral|qwen.*vl/i)
150
- caps[:streaming] = true unless caps[:embeddings]
151
- caps
139
+ def extract_catalog_capabilities(_model_info)
140
+ # Regex-based name matching is not authoritative evidence.
141
+ # Unverified capability support is unknown, not promoted to supported.
142
+ {}
152
143
  end
153
144
 
154
145
  def embedding_model?(model_id)
@@ -156,84 +147,112 @@ module Legion
156
147
  end
157
148
 
158
149
  def provider_envelope_capabilities
159
- { streaming: true }
150
+ # No capabilities are advertised at the envelope level without endpoint evidence.
151
+ {}
160
152
  end
161
153
 
162
- def health_payload(raw)
163
- ready = health_ready?(raw)
164
- status = health_status(ready)
165
-
154
+ def offering_metadata_for(model_info)
166
155
  {
167
- provider: :mlx,
168
- instance_id: provider_instance_id,
169
- status: status,
170
- ready: ready,
171
- circuit_state: circuit_state(status),
172
- raw: raw
173
- }
156
+ raw_model: model_info.id,
157
+ parameter_count: model_info.respond_to?(:parameter_count) ? model_info.parameter_count : nil,
158
+ quantization: model_info.respond_to?(:quantization) ? model_info.quantization : nil
159
+ }.compact
174
160
  end
161
+ end
175
162
 
176
- def health_ready?(raw)
177
- raw.is_a?(Hash) ? raw.fetch('ready', raw.fetch(:ready, true)) : true
163
+ # MLX provider implementation for local OpenAI-compatible servers.
164
+ class Provider < Legion::Extensions::Llm::Provider
165
+ include Legion::Extensions::Llm::Provider::OpenAICompatible
166
+ include CapabilityConfig
167
+ include HealthHelpers
168
+ include CapabilityResolution
169
+
170
+ class << self
171
+ def slug = 'mlx'
172
+ def local? = true
173
+ def default_transport = :http
174
+ def default_tier = :local
175
+ def configuration_options = %i[mlx_api_base mlx_api_key]
176
+ def configuration_requirements = []
177
+ def capabilities = Capabilities
178
178
  end
179
179
 
180
- def health_status(ready)
181
- ready ? 'healthy' : 'unhealthy'
180
+ def settings
181
+ Mlx.default_settings
182
182
  end
183
183
 
184
- def circuit_state(status)
185
- status == 'healthy' ? 'closed' : 'open'
184
+ def api_base
185
+ normalize_url(config.mlx_api_base || settings[:instances][:default][:endpoint])
186
186
  end
187
187
 
188
- def provider_capability_config
189
- conf = Legion::Extensions::Llm::CredentialSources.setting(:extensions, :llm, :mlx)
190
- conf.is_a?(Hash) ? conf.to_h.except(:instances, 'instances') : {}
191
- rescue StandardError => e
192
- handle_exception(e, level: :warn, handled: true, operation: 'mlx.provider_capability_config')
193
- {}
188
+ def headers
189
+ hdrs = identity_headers
190
+ token = config.mlx_api_key
191
+ hdrs['Authorization'] = "Bearer #{token}" unless token.nil? || token.to_s.empty?
192
+ hdrs
194
193
  end
195
194
 
196
- def instance_capability_config
197
- cfg = config
198
- result = {}
199
- %i[capabilities enable_thinking enable_tools enable_streaming enable_vision enable_embeddings
200
- thinking_flag tools_flag streaming_flag vision_flag embedding_flag embeddings_flag
201
- tool_flag images_flag image_flag].each do |key|
202
- next unless cfg.respond_to?(key)
195
+ def health_url = '/health'
203
196
 
204
- val = cfg.send(key)
205
- result[key] = val unless val.nil?
206
- rescue StandardError
207
- next
208
- end
209
- result
197
+ def health(live: false)
198
+ log.info("Checking MLX health live=#{live} at #{api_base}#{health_url}")
199
+ raw = connection.get(health_url).body
200
+ health_payload(raw)
201
+ rescue StandardError => e
202
+ handle_exception(e, level: :warn, handled: true, operation: 'mlx.provider.health')
203
+ {
204
+ provider: :mlx,
205
+ instance_id: provider_instance_id,
206
+ status: 'unhealthy',
207
+ ready: false,
208
+ circuit_state: 'open',
209
+ error: e.class.name,
210
+ message: e.message
211
+ }
210
212
  end
211
213
 
212
- def model_capability_config(model_id)
213
- models_conf = fetch_models_config
214
- return {} unless models_conf
214
+ def readiness(live: false)
215
+ log.info("Checking MLX readiness (live=#{live})")
216
+ super
217
+ end
215
218
 
216
- hash = models_conf.to_h
217
- hash[model_id.to_s] || hash[model_id.to_sym] || {}
218
- rescue StandardError => e
219
- handle_exception(e, level: :warn, handled: true, operation: 'mlx.model_capability_config')
220
- {}
219
+ def list_models(**)
220
+ log.info('Listing available MLX models')
221
+ models = super
222
+ log.info("Discovered #{Array(models).size} MLX models")
223
+ models
221
224
  end
222
225
 
223
- def fetch_models_config
224
- conf = config.models if config.respond_to?(:models)
225
- conf ||= config[:models] if config.respond_to?(:[])
226
- conf if conf.respond_to?(:to_h)
227
- rescue StandardError
228
- nil
226
+ def offering_from_model(model_info, health: {})
227
+ policy = resolve_capability_policy(model_info)
228
+ Legion::Extensions::Llm::Routing::ModelOffering.new(**build_offering_kwargs(
229
+ model_info: model_info, policy: policy, health: health
230
+ ))
229
231
  end
230
232
 
231
- def offering_metadata_for(model_info)
233
+ private
234
+
235
+ def build_offering_kwargs(model_info:, policy:, health:)
232
236
  {
233
- raw_model: model_info.id,
234
- parameter_count: model_info.respond_to?(:parameter_count) ? model_info.parameter_count : nil,
235
- quantization: model_info.respond_to?(:quantization) ? model_info.quantization : nil
236
- }.compact
237
+ provider_family: :mlx,
238
+ instance_id: provider_instance_id,
239
+ transport: offering_transport,
240
+ tier: offering_tier,
241
+ model: model_info.id,
242
+ canonical_model_alias: model_info.respond_to?(:name) ? model_info.name : nil,
243
+ model_family: model_info.respond_to?(:family) ? model_info.family : nil,
244
+ usage_type: embedding_model?(model_info.id) ? :embedding : :inference,
245
+ capabilities: policy[:capabilities],
246
+ capability_sources: policy[:sources],
247
+ limits: extract_model_limits(model_info),
248
+ health: health,
249
+ metadata: offering_metadata_for(model_info).merge(capability_sources: policy[:sources])
250
+ }
251
+ end
252
+
253
+ def extract_model_limits(model_info)
254
+ ctx = model_info.respond_to?(:context_length) ? model_info.context_length : nil
255
+ { context_window: ctx }.compact
237
256
  end
238
257
  end
239
258
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'legion/extensions/llm/fleet/provider_responder'
4
4
  require 'legion/extensions/llm/mlx'
5
+ require 'legion/logging'
5
6
 
6
7
  module Legion
7
8
  module Extensions
@@ -9,17 +10,35 @@ module Legion
9
10
  module Mlx
10
11
  module Runners
11
12
  # Runner entrypoint for MLX fleet request execution.
13
+ # Delegates to the shared ProviderResponder with exact-offering
14
+ # registry support for SSOT v3 execution contracts.
15
+ #
16
+ # The fleet Subscription actor dispatches this as
17
+ # `handle_fleet_request(**message)`, where message is the decoded
18
+ # request envelope merged with transport metadata, so the
19
+ # signature is kwargs-only. Ack/reject is owned by the
20
+ # Subscription actor, so the responder is called with nil
21
+ # delivery/properties.
12
22
  module FleetWorker
23
+ include Legion::Logging::Helper
24
+ extend Legion::Logging::Helper
25
+
13
26
  module_function
14
27
 
15
- def handle_fleet_request(payload, delivery: nil, properties: nil)
28
+ def handle_fleet_request(**message)
29
+ log.debug do
30
+ "handling MLX fleet request request_id=#{message[:request_id].inspect} " \
31
+ "provider_instance=#{message[:provider_instance].inspect} " \
32
+ "operation=#{message[:operation].inspect}"
33
+ end
16
34
  Legion::Extensions::Llm::Fleet::ProviderResponder.call(
17
- payload: payload,
35
+ payload: message,
18
36
  provider_family: Mlx::PROVIDER_FAMILY,
19
37
  provider_class: Mlx::Provider,
20
38
  provider_instances: -> { Mlx.discover_instances },
21
- delivery: delivery,
22
- properties: properties
39
+ registry: Legion::Extensions::Llm::Inventory::Registry,
40
+ delivery: nil,
41
+ properties: nil
23
42
  )
24
43
  end
25
44
  end
@@ -4,7 +4,7 @@ module Legion
4
4
  module Extensions
5
5
  module Llm
6
6
  module Mlx
7
- VERSION = '0.3.13'
7
+ VERSION = '0.5.2'
8
8
  end
9
9
  end
10
10
  end
@@ -3,7 +3,7 @@
3
3
  require 'legion/extensions/llm'
4
4
  require 'legion/extensions/llm/mlx/provider'
5
5
  require 'legion/extensions/llm/mlx/version'
6
- require_relative 'mlx/actors/discovery_refresh'
6
+ require 'legion/extensions/llm/mlx/actors/discovery_refresh'
7
7
 
8
8
  module Legion
9
9
  module Extensions
@@ -11,7 +11,6 @@ module Legion
11
11
  # Mlx provider extension namespace.
12
12
  module Mlx
13
13
  extend Legion::Logging::Helper
14
- extend ::Legion::Extensions::Core if ::Legion::Extensions.const_defined?(:Core, false)
15
14
  extend Legion::Extensions::Llm::AutoRegistration
16
15
 
17
16
  PROVIDER_FAMILY = :mlx
@@ -39,48 +38,83 @@ module Legion
39
38
  Provider
40
39
  end
41
40
 
41
+ # Single source of truth for MLX instance discovery. The SSOT
42
+ # discovery actor and the fleet responder both read this: only
43
+ # operator-configured instances. No port-scanning, no fabricated
44
+ # instances, no tier override.
42
45
  def self.discover_instances
46
+ configured_instances
47
+ end
48
+
49
+ # Only instances the operator actually configured are claimable.
50
+ # The synthetic instances.default section (provider_settings nests
51
+ # the extension's own instance defaults there at boot) is skipped
52
+ # with a once-per-boot warn while it is still the unmodified
53
+ # extension default — an unconfigured phantom must never be
54
+ # auto-registered, and a localhost endpoint is never a fallback
55
+ # identity.
56
+ def self.configured_instances
57
+ provider_cfg = Legion::Settings.dig(:extensions, :llm, :mlx) || {}
43
58
  instances = {}
44
- discover_local_instance(instances)
45
- discover_settings_instances(instances)
59
+ cfg_instances = provider_cfg[:instances]
60
+ if cfg_instances.is_a?(Hash)
61
+ cfg_instances.each do |name, config|
62
+ normalized = normalize_instance_config(config)
63
+ instances[name.to_sym] = normalized
64
+ end
65
+ end
46
66
  instances
47
67
  end
48
68
 
49
- def self.discover_local_instance(instances)
50
- return unless CredentialSources.socket_open?('localhost', 8000, timeout: 0.1)
51
-
52
- instances[:local] = {
53
- base_url: 'http://localhost:8000',
54
- tier: :local,
55
- capabilities: [:completion]
56
- }
69
+ # The synthetic default is the extension's OWN registered instance
70
+ # defaults (endpoint http://localhost:8000 + fleet/limits blocks),
71
+ # deep-merged into instances.default by provider_settings. It is
72
+ # "configured" only when the operator changed something — a
73
+ # configured 'default' passes the provider layer and reaches the
74
+ # claim path (v2 parity: 'default' is a plain instance label). ONE
75
+ # predicate, TWO consumers: the actor's claim path (tick_refresh
76
+ # iterates configured_instances into claim_and_activate_instance)
77
+ # and the fleet responder (discover_instances → configured_instances)
78
+ # both reach it through this single filter point — no drift.
79
+ def self.unconfigured_default?(name:, normalized:)
80
+ name.to_sym == :default && normalized == normalized_synthetic_default_instance
57
81
  end
58
82
 
59
- def self.discover_settings_instances(instances)
60
- cfg = CredentialSources.setting(:extensions, :llm, :mlx, :instances)
61
- return unless cfg.is_a?(Hash)
83
+ def self.normalized_synthetic_default_instance
84
+ @normalized_synthetic_default_instance ||= normalize_instance_config(
85
+ default_settings.dig(:instances, :default) || {}
86
+ )
87
+ end
62
88
 
63
- cfg.each do |name, config|
64
- instances[name.to_sym] = normalize_instance_config(config).merge(tier: :direct)
65
- end
89
+ def self.normalize_instance_config(config)
90
+ normalized = config.to_h.transform_keys(&:to_sym)
91
+ promote_api_base_aliases(normalized)
92
+ normalized[:mlx_api_base] = normalize_api_base(normalized[:mlx_api_base]) if normalized[:mlx_api_base]
93
+ normalized[:mlx_api_key] ||= normalized.delete(:api_key)
94
+ resolve_instance_credentials(normalized)
95
+ normalized[:tier] ||= :local
96
+ normalized.compact
66
97
  end
67
98
 
68
- def self.normalize_instance_config(config) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
69
- normalized = config.to_h.transform_keys { |key| key.respond_to?(:to_sym) ? key.to_sym : key }
99
+ def self.promote_api_base_aliases(normalized)
70
100
  normalized[:mlx_api_base] ||= normalized.delete(:base_url)
71
101
  normalized[:mlx_api_base] ||= normalized.delete(:api_base)
72
102
  normalized[:mlx_api_base] ||= normalized.delete(:endpoint)
73
- normalized[:mlx_api_key] ||= normalized.delete(:api_key)
74
- normalized[:mlx_api_base] = normalize_api_base(normalized[:mlx_api_base]) if normalized[:mlx_api_base]
75
- normalized.compact
76
103
  end
77
104
 
78
105
  def self.normalize_api_base(url)
79
106
  url.to_s.sub(%r{/v1/?\z}, '')
80
107
  end
81
108
 
82
- private_class_method :discover_local_instance, :discover_settings_instances,
83
- :normalize_instance_config, :normalize_api_base
109
+ def self.resolve_instance_credentials(normalized)
110
+ creds = normalized.delete(:credentials)
111
+ return unless creds.is_a?(Hash)
112
+
113
+ normalized[:mlx_api_key] ||= creds.transform_keys(&:to_sym)[:api_key]
114
+ end
115
+
116
+ private_class_method :normalize_instance_config, :promote_api_base_aliases, :normalize_api_base,
117
+ :resolve_instance_credentials
84
118
 
85
119
  Legion::Extensions::Llm::Configuration.register_provider_options(Provider.configuration_options)
86
120
  end
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.3.13
4
+ version: 0.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - LegionIO
@@ -9,6 +9,20 @@ bindir: bin
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: faraday
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: 1.10.0
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: 1.10.0
12
26
  - !ruby/object:Gem::Dependency
13
27
  name: legion-json
14
28
  requirement: !ruby/object:Gem::Requirement
@@ -43,14 +57,14 @@ dependencies:
43
57
  requirements:
44
58
  - - ">="
45
59
  - !ruby/object:Gem::Version
46
- version: 1.3.14
60
+ version: 1.4.2
47
61
  type: :runtime
48
62
  prerelease: false
49
63
  version_requirements: !ruby/object:Gem::Requirement
50
64
  requirements:
51
65
  - - ">="
52
66
  - !ruby/object:Gem::Version
53
- version: 1.3.14
67
+ version: 1.4.2
54
68
  - !ruby/object:Gem::Dependency
55
69
  name: legion-transport
56
70
  requirement: !ruby/object:Gem::Requirement
@@ -71,14 +85,14 @@ dependencies:
71
85
  requirements:
72
86
  - - ">="
73
87
  - !ruby/object:Gem::Version
74
- version: 0.6.0
88
+ version: 0.7.1
75
89
  type: :runtime
76
90
  prerelease: false
77
91
  version_requirements: !ruby/object:Gem::Requirement
78
92
  requirements:
79
93
  - - ">="
80
94
  - !ruby/object:Gem::Version
81
- version: 0.6.0
95
+ version: 0.7.1
82
96
  description: MLX provider integration for the LegionIO LLM routing framework.
83
97
  email:
84
98
  - matthewdiverson@gmail.com