lex-llm-mlx 0.3.7 → 0.3.13
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 +35 -0
- data/Gemfile +0 -7
- data/lex-llm-mlx.gemspec +1 -1
- data/lib/legion/extensions/llm/mlx/actors/discovery_refresh.rb +170 -0
- data/lib/legion/extensions/llm/mlx/provider.rb +151 -2
- data/lib/legion/extensions/llm/mlx/version.rb +1 -1
- data/lib/legion/extensions/llm/mlx.rb +5 -8
- metadata +4 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5490746e9c970066d163970177812051c9793d6f25f036c94139b63d01b81e4b
|
|
4
|
+
data.tar.gz: b766dee30291fb2b73cdefc7807f07519776a3c3ba16e87b43c4ef0f0f9efc81
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 51dea6c8da8a5e79e54da1281bbcf396bc00b6ada942f1c439fa1bb5556a590f1e839d367f54660731a9eda493c383f03fd88de9feeb5c50f8e9bc57e4f9977c
|
|
7
|
+
data.tar.gz: 4a228ecb85b060a8eab56ddf1e99f089c9e061ffa106f40fdde158d215a50bd7729f80f44bf221e958c496566ece3913663ee015c31d3ec52ffc275de7bb164d
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.3.13] - 2026-06-20
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
- Align MLX offerings to the current `lex-llm` contract: `discover_offerings` now works with the shared
|
|
7
|
+
provider flow, offerings honor configured tier/transport overrides, and provider health is carried onto
|
|
8
|
+
discovered offerings in the shared shape.
|
|
9
|
+
- Normalize MLX capability override expectations to the shared `:embedding` offering vocabulary.
|
|
10
|
+
|
|
11
|
+
## [0.3.12] - 2026-06-19
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
- Adopt `Legion::Extensions::Llm::Inventory::ScopedRefresher` mixin (lex-llm 0.6.0). Discovery
|
|
15
|
+
refresh actors now write directly to the live `Inventory` catalog via `Inventory.write_lane`.
|
|
16
|
+
- Pin `lex-llm >= 0.6.0` and `legion-llm >= 0.14.0` in gemspec.
|
|
17
|
+
- Standard `weight: 100` default added to provider instance settings schema.
|
|
18
|
+
|
|
19
|
+
## 0.3.11 - 2026-06-16
|
|
20
|
+
|
|
21
|
+
- Dependency updates and code quality improvements.
|
|
22
|
+
|
|
23
|
+
## 0.3.10 - 2026-06-15
|
|
24
|
+
|
|
25
|
+
- **CapabilityPolicy integration** — Name-pattern heuristics tagged as `:provider_catalog`; streaming from `:provider_envelope`. Settings overrides at provider/instance/model level supported.
|
|
26
|
+
|
|
27
|
+
## 0.3.9 - 2026-06-13
|
|
28
|
+
|
|
29
|
+
- **Gemfile cleanup** — Remove local path overrides; dependencies resolve from gemspec via rubygems.
|
|
30
|
+
- **Dependency bump** — Require `lex-llm >= 0.5.0` for canonical types support.
|
|
31
|
+
- **Canonical tool support** — Use `ToolSchema.extract` and add `:tools` capability.
|
|
32
|
+
- 20 examples, 0 failures; 13 files, 0 rubocop offenses.
|
|
33
|
+
|
|
34
|
+
## 0.3.8 - 2026-06-02
|
|
35
|
+
|
|
36
|
+
- Add per-provider scoped discovery refresh actor
|
|
37
|
+
|
|
3
38
|
## 0.3.7 - 2026-05-21
|
|
4
39
|
|
|
5
40
|
- Add `default_transport`/`default_tier` class declarations
|
data/Gemfile
CHANGED
|
@@ -2,13 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
source 'https://rubygems.org'
|
|
4
4
|
|
|
5
|
-
group :test do
|
|
6
|
-
llm_base_path = ENV.fetch('LEX_LLM_PATH', File.expand_path('../lex-llm', __dir__))
|
|
7
|
-
transport_path = ENV.fetch('LEGION_TRANSPORT_PATH', File.expand_path('../../legion-transport', __dir__))
|
|
8
|
-
gem 'legion-transport', path: transport_path if File.directory?(transport_path)
|
|
9
|
-
gem 'lex-llm', path: llm_base_path if File.directory?(llm_base_path)
|
|
10
|
-
end
|
|
11
|
-
|
|
12
5
|
gemspec
|
|
13
6
|
|
|
14
7
|
group :development do
|
data/lex-llm-mlx.gemspec
CHANGED
|
@@ -27,5 +27,5 @@ Gem::Specification.new do |spec|
|
|
|
27
27
|
spec.add_dependency 'legion-logging', '>= 1.3.2'
|
|
28
28
|
spec.add_dependency 'legion-settings', '>= 1.3.14'
|
|
29
29
|
spec.add_dependency 'legion-transport', '>= 1.4.14'
|
|
30
|
-
spec.add_dependency 'lex-llm', '>= 0.
|
|
30
|
+
spec.add_dependency 'lex-llm', '>= 0.6.0'
|
|
31
31
|
end
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'digest'
|
|
4
|
+
|
|
5
|
+
begin
|
|
6
|
+
require 'legion/extensions/actors/every'
|
|
7
|
+
rescue LoadError => e
|
|
8
|
+
warn(e.message) if $VERBOSE
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
begin
|
|
12
|
+
require 'legion/extensions/llm/inventory/scoped_refresher'
|
|
13
|
+
rescue LoadError => e
|
|
14
|
+
warn(e.message) if $VERBOSE
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
return unless defined?(Legion::Extensions::Actors::Every)
|
|
18
|
+
|
|
19
|
+
module Legion
|
|
20
|
+
module Extensions
|
|
21
|
+
module Llm
|
|
22
|
+
module Mlx
|
|
23
|
+
module Actor
|
|
24
|
+
class DiscoveryRefresh < Legion::Extensions::Actors::Every # rubocop:disable Style/Documentation, Metrics/ClassLength
|
|
25
|
+
include Legion::Logging::Helper
|
|
26
|
+
|
|
27
|
+
if defined?(Legion::Extensions::Llm::Inventory::ScopedRefresher)
|
|
28
|
+
include Legion::Extensions::Llm::Inventory::ScopedRefresher
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def self.every_seconds = 60
|
|
32
|
+
|
|
33
|
+
def runner_class = self.class
|
|
34
|
+
def runner_function = 'manual'
|
|
35
|
+
def run_now? = true
|
|
36
|
+
def use_runner? = false
|
|
37
|
+
def check_subtask? = false
|
|
38
|
+
def generate_task? = false
|
|
39
|
+
|
|
40
|
+
def time
|
|
41
|
+
return self.class.every_seconds unless defined?(Legion::Settings)
|
|
42
|
+
|
|
43
|
+
Legion::Settings.dig(:extensions, :llm, :mlx, :discovery_interval) || self.class.every_seconds
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def scope_key(**)
|
|
47
|
+
{ provider: :mlx }
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def compute_lanes_for_scope(**)
|
|
51
|
+
return [] unless defined?(Legion::LLM::Call::Registry)
|
|
52
|
+
|
|
53
|
+
mlx_instances.flat_map { |entry| lanes_for_instance(entry) }
|
|
54
|
+
rescue StandardError => e
|
|
55
|
+
handle_exception(e, level: :warn, handled: true, operation: 'mlx.discovery_refresh.compute_lanes')
|
|
56
|
+
[]
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def credential_hash(**)
|
|
60
|
+
mlx_settings = Legion::Settings.dig(:extensions, :llm, :mlx) || {}
|
|
61
|
+
Digest::SHA256.hexdigest(mlx_settings[:api_key].to_s + mlx_settings[:instances].to_s)[0, 16]
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def manual(**)
|
|
65
|
+
tick if respond_to?(:tick)
|
|
66
|
+
rescue StandardError => e
|
|
67
|
+
handle_exception(e, level: :warn, handled: true, operation: 'mlx.actor.discovery_refresh')
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
def mlx_instances
|
|
73
|
+
Legion::LLM::Call::Registry.all_instances.select do |e|
|
|
74
|
+
(e[:provider] || '').to_sym == :mlx
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def offerings_for(adapter, instance_id)
|
|
79
|
+
Array(adapter.discover_offerings(live: true))
|
|
80
|
+
rescue StandardError => e
|
|
81
|
+
handle_exception(e, level: :warn, handled: true,
|
|
82
|
+
operation: 'mlx.discovery_refresh.discover_offerings',
|
|
83
|
+
instance: instance_id)
|
|
84
|
+
[]
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def lanes_for_instance(entry)
|
|
88
|
+
adapter = entry[:adapter]
|
|
89
|
+
instance_id = entry[:instance] || entry[:instance_id] || entry[:id]
|
|
90
|
+
return [] unless adapter.respond_to?(:discover_offerings)
|
|
91
|
+
|
|
92
|
+
offerings_for(adapter, instance_id).filter_map do |raw_offering|
|
|
93
|
+
offering = offering_to_hash(raw_offering)
|
|
94
|
+
next unless offering
|
|
95
|
+
|
|
96
|
+
build_lanes(offering, instance_id)
|
|
97
|
+
end.flatten
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def offering_to_hash(offering)
|
|
101
|
+
return nil if offering.nil?
|
|
102
|
+
return offering if offering.is_a?(Hash)
|
|
103
|
+
|
|
104
|
+
hash = offering.to_h
|
|
105
|
+
hash[:type] ||= hash[:usage_type]
|
|
106
|
+
hash[:enabled] = offering.respond_to?(:enabled?) ? offering.enabled? : true
|
|
107
|
+
hash
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def build_lanes(offering, instance_id)
|
|
111
|
+
type = offering_type(offering[:type])
|
|
112
|
+
tier = offering[:tier] || :local
|
|
113
|
+
lane = build_lane(offering, instance_id, type, tier)
|
|
114
|
+
lanes = [lane]
|
|
115
|
+
lanes << fleet_lane(lane, instance_id, type) if fleet_enabled? && type == :inference
|
|
116
|
+
lanes
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def build_lane(offering, instance_id, type, tier)
|
|
120
|
+
{
|
|
121
|
+
id: compose_lane_id(tier: tier, instance_id: instance_id,
|
|
122
|
+
type: type, model: offering[:model]),
|
|
123
|
+
tier: tier,
|
|
124
|
+
provider_family: :mlx,
|
|
125
|
+
instance_id: instance_id,
|
|
126
|
+
model: offering[:model],
|
|
127
|
+
canonical_model_alias: offering[:canonical_model_alias],
|
|
128
|
+
type: type,
|
|
129
|
+
capabilities: normalize_capabilities(offering[:capabilities]),
|
|
130
|
+
limits: offering[:limits] || {},
|
|
131
|
+
enabled: offering.fetch(:enabled, true),
|
|
132
|
+
cost: offering[:cost] || {}
|
|
133
|
+
}
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def fleet_lane(lane, instance_id, type)
|
|
137
|
+
lane.merge(
|
|
138
|
+
tier: :fleet,
|
|
139
|
+
id: compose_lane_id(tier: :fleet, instance_id: instance_id,
|
|
140
|
+
type: type, model: lane[:model])
|
|
141
|
+
)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def offering_type(raw)
|
|
145
|
+
%i[embed embedding].include?(raw.to_s.to_sym) ? :embedding : :inference
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def normalize_capabilities(caps)
|
|
149
|
+
return [] unless defined?(Legion::LLM::Inventory::Capabilities)
|
|
150
|
+
|
|
151
|
+
Legion::LLM::Inventory::Capabilities.normalize(caps)
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def compose_lane_id(tier:, instance_id:, type:, model:)
|
|
155
|
+
Legion::Extensions::Llm::Inventory::ScopedRefresher.compose_id(
|
|
156
|
+
tier: tier, provider_family: :mlx, instance_id: instance_id,
|
|
157
|
+
type: type, model: model
|
|
158
|
+
)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def fleet_enabled?
|
|
162
|
+
mlx_settings = Legion::Settings.dig(:extensions, :llm, :mlx) || {}
|
|
163
|
+
mlx_settings.dig(:fleet, :dispatch, :enabled)
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
@@ -7,7 +7,7 @@ module Legion
|
|
|
7
7
|
module Llm
|
|
8
8
|
module Mlx
|
|
9
9
|
# MLX provider implementation for local OpenAI-compatible servers.
|
|
10
|
-
class Provider < Legion::Extensions::Llm::Provider
|
|
10
|
+
class Provider < Legion::Extensions::Llm::Provider # rubocop:disable Metrics/ClassLength
|
|
11
11
|
include Legion::Extensions::Llm::Provider::OpenAICompatible
|
|
12
12
|
|
|
13
13
|
class << self
|
|
@@ -69,7 +69,19 @@ module Legion
|
|
|
69
69
|
|
|
70
70
|
def health(live: false)
|
|
71
71
|
log.info("Checking MLX health live=#{live} at #{api_base}#{health_url}")
|
|
72
|
-
connection.get(health_url).body
|
|
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')
|
|
76
|
+
{
|
|
77
|
+
provider: :mlx,
|
|
78
|
+
instance_id: provider_instance_id,
|
|
79
|
+
status: 'unhealthy',
|
|
80
|
+
ready: false,
|
|
81
|
+
circuit_state: 'open',
|
|
82
|
+
error: e.class.name,
|
|
83
|
+
message: e.message
|
|
84
|
+
}
|
|
73
85
|
end
|
|
74
86
|
|
|
75
87
|
def readiness(live: false)
|
|
@@ -86,6 +98,143 @@ module Legion
|
|
|
86
98
|
self.class.registry_publisher.publish_models_async(models, readiness: readiness(live: false))
|
|
87
99
|
end
|
|
88
100
|
end
|
|
101
|
+
|
|
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
|
+
)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def resolve_capability_policy(model_info)
|
|
124
|
+
Legion::Extensions::Llm::CapabilityPolicy.resolve(
|
|
125
|
+
real: extract_real_capabilities(model_info),
|
|
126
|
+
provider_catalog: extract_catalog_capabilities(model_info),
|
|
127
|
+
probe: {},
|
|
128
|
+
provider_envelope: provider_envelope_capabilities,
|
|
129
|
+
provider_config: provider_capability_config,
|
|
130
|
+
instance_config: instance_capability_config,
|
|
131
|
+
model_config: model_capability_config(model_info.id)
|
|
132
|
+
)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def extract_real_capabilities(model_info)
|
|
136
|
+
return {} unless model_info.respond_to?(:metadata)
|
|
137
|
+
|
|
138
|
+
meta = model_info.metadata
|
|
139
|
+
return {} unless meta.is_a?(Hash)
|
|
140
|
+
|
|
141
|
+
caps = meta[:capabilities]
|
|
142
|
+
caps.is_a?(Hash) ? caps : {}
|
|
143
|
+
end
|
|
144
|
+
|
|
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
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def embedding_model?(model_id)
|
|
155
|
+
model_id.to_s.match?(/embed|bge|e5|nomic/i)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def provider_envelope_capabilities
|
|
159
|
+
{ streaming: true }
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def health_payload(raw)
|
|
163
|
+
ready = health_ready?(raw)
|
|
164
|
+
status = health_status(ready)
|
|
165
|
+
|
|
166
|
+
{
|
|
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
|
+
}
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def health_ready?(raw)
|
|
177
|
+
raw.is_a?(Hash) ? raw.fetch('ready', raw.fetch(:ready, true)) : true
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def health_status(ready)
|
|
181
|
+
ready ? 'healthy' : 'unhealthy'
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def circuit_state(status)
|
|
185
|
+
status == 'healthy' ? 'closed' : 'open'
|
|
186
|
+
end
|
|
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
|
+
{}
|
|
194
|
+
end
|
|
195
|
+
|
|
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)
|
|
203
|
+
|
|
204
|
+
val = cfg.send(key)
|
|
205
|
+
result[key] = val unless val.nil?
|
|
206
|
+
rescue StandardError
|
|
207
|
+
next
|
|
208
|
+
end
|
|
209
|
+
result
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def model_capability_config(model_id)
|
|
213
|
+
models_conf = fetch_models_config
|
|
214
|
+
return {} unless models_conf
|
|
215
|
+
|
|
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
|
+
{}
|
|
221
|
+
end
|
|
222
|
+
|
|
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
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
def offering_metadata_for(model_info)
|
|
232
|
+
{
|
|
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
|
+
end
|
|
89
238
|
end
|
|
90
239
|
end
|
|
91
240
|
end
|
|
@@ -3,6 +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
7
|
|
|
7
8
|
module Legion
|
|
8
9
|
module Extensions
|
|
@@ -28,10 +29,7 @@ module Legion
|
|
|
28
29
|
fleet: {
|
|
29
30
|
enabled: false,
|
|
30
31
|
respond_to_requests: false,
|
|
31
|
-
capabilities: %i[chat stream_chat embed]
|
|
32
|
-
lanes: [],
|
|
33
|
-
concurrency: 1,
|
|
34
|
-
queue_suffix: nil
|
|
32
|
+
capabilities: %i[chat stream_chat embed]
|
|
35
33
|
}
|
|
36
34
|
}
|
|
37
35
|
)
|
|
@@ -49,10 +47,10 @@ module Legion
|
|
|
49
47
|
end
|
|
50
48
|
|
|
51
49
|
def self.discover_local_instance(instances)
|
|
52
|
-
return unless CredentialSources.socket_open?('localhost',
|
|
50
|
+
return unless CredentialSources.socket_open?('localhost', 8000, timeout: 0.1)
|
|
53
51
|
|
|
54
52
|
instances[:local] = {
|
|
55
|
-
base_url: 'http://localhost:
|
|
53
|
+
base_url: 'http://localhost:8000',
|
|
56
54
|
tier: :local,
|
|
57
55
|
capabilities: [:completion]
|
|
58
56
|
}
|
|
@@ -84,8 +82,7 @@ module Legion
|
|
|
84
82
|
private_class_method :discover_local_instance, :discover_settings_instances,
|
|
85
83
|
:normalize_instance_config, :normalize_api_base
|
|
86
84
|
|
|
87
|
-
Legion::Extensions::Llm::Configuration.register_provider_options(Provider.configuration_options)
|
|
88
|
-
Legion::Extensions::Llm::Configuration.respond_to?(:register_provider_options)
|
|
85
|
+
Legion::Extensions::Llm::Configuration.register_provider_options(Provider.configuration_options)
|
|
89
86
|
end
|
|
90
87
|
end
|
|
91
88
|
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.
|
|
4
|
+
version: 0.3.13
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- LegionIO
|
|
@@ -71,14 +71,14 @@ dependencies:
|
|
|
71
71
|
requirements:
|
|
72
72
|
- - ">="
|
|
73
73
|
- !ruby/object:Gem::Version
|
|
74
|
-
version: 0.
|
|
74
|
+
version: 0.6.0
|
|
75
75
|
type: :runtime
|
|
76
76
|
prerelease: false
|
|
77
77
|
version_requirements: !ruby/object:Gem::Requirement
|
|
78
78
|
requirements:
|
|
79
79
|
- - ">="
|
|
80
80
|
- !ruby/object:Gem::Version
|
|
81
|
-
version: 0.
|
|
81
|
+
version: 0.6.0
|
|
82
82
|
description: MLX provider integration for the LegionIO LLM routing framework.
|
|
83
83
|
email:
|
|
84
84
|
- matthewdiverson@gmail.com
|
|
@@ -97,6 +97,7 @@ files:
|
|
|
97
97
|
- README.md
|
|
98
98
|
- lex-llm-mlx.gemspec
|
|
99
99
|
- lib/legion/extensions/llm/mlx.rb
|
|
100
|
+
- lib/legion/extensions/llm/mlx/actors/discovery_refresh.rb
|
|
100
101
|
- lib/legion/extensions/llm/mlx/actors/fleet_worker.rb
|
|
101
102
|
- lib/legion/extensions/llm/mlx/provider.rb
|
|
102
103
|
- lib/legion/extensions/llm/mlx/runners/fleet_worker.rb
|