lex-llm-azure-foundry 0.2.10 → 0.2.14
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 +26 -0
- data/lex-llm-azure-foundry.gemspec +1 -1
- data/lib/legion/extensions/llm/azure_foundry/actors/discovery_refresh.rb +124 -5
- data/lib/legion/extensions/llm/azure_foundry/provider.rb +65 -31
- data/lib/legion/extensions/llm/azure_foundry/version.rb +1 -1
- data/lib/legion/extensions/llm/azure_foundry.rb +3 -2
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 30c68d11d7549c672c912006d7ca6e843fbd976cd7e5e1845db580b9f86543f8
|
|
4
|
+
data.tar.gz: 5451587d09659bd54f9f6a5d52c165f1eee58a66a2667797a65a7f2f84c9fbce
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0a9509a27ea507bfa9cf0a68564cb56cafad2ca30fe8f158a2a1a33dcdb701dc3b25289ce0707a524c9488f54f12421005702b31b3bf6d2b35eb869bc79f77e8
|
|
7
|
+
data.tar.gz: 0dd91d0a237fa15c9a6fcb32f8c77d81c15274e97fc525d08a254787e91f410449b01448d43e677f9f785343738f33e0de6a0bb07076af45dc7c2ccebbf67cf6
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.2.14] - 2026-07-03
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- Emit relative request paths from `path_for` (no leading slash). `Connection` builds Faraday with `api_base` as the base URL; on the `openai_v1` surface that base carries the `/openai/v1` path, and a leading-slash path was treated as absolute and dropped it — 404ing live discovery (empty offerings) and chat. Paths are now relative so the base path survives on both surfaces.
|
|
7
|
+
- Resolve `models_url`/`health_url` per surface: `models` on `openai_v1`, `models/info` on `model_inference`. Previously always `info`, which 404s on the `openai_v1` surface.
|
|
8
|
+
|
|
9
|
+
## [0.2.13] - 2026-06-20
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
- Stub shared registry publishing through `RegistryPublisher#schedule` in specs so async availability-event coverage stays stable after the shared publisher moved off raw `Thread.new`.
|
|
13
|
+
|
|
14
|
+
## [0.2.12] - 2026-06-20
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
- Align Azure Foundry instance discovery with the shared `lex-llm` contract by preserving explicit tier overrides while defaulting unconfigured instances to `:cloud`.
|
|
18
|
+
- Restore offline deployment-backed offering discovery and carry the configured provider instance id through Azure offering metadata.
|
|
19
|
+
- Normalize Azure Foundry capability and health metadata to the current shared offering contract.
|
|
20
|
+
|
|
21
|
+
## [0.2.11] - 2026-06-19
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
- Adopt `Legion::Extensions::Llm::Inventory::ScopedRefresher` mixin (lex-llm 0.6.0). Discovery
|
|
25
|
+
refresh actors now write directly to the live `Inventory` catalog via `Inventory.write_lane`.
|
|
26
|
+
- Pin `lex-llm >= 0.6.0` and `legion-llm >= 0.14.0` in gemspec.
|
|
27
|
+
- Standard `weight: 100` default added to provider instance settings schema.
|
|
28
|
+
|
|
3
29
|
## 0.2.10 - 2026-06-16
|
|
4
30
|
|
|
5
31
|
- Dependency updates and code quality improvements.
|
|
@@ -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
|
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'digest'
|
|
4
|
+
|
|
3
5
|
begin
|
|
4
6
|
require 'legion/extensions/actors/every'
|
|
5
7
|
rescue LoadError => e
|
|
6
8
|
warn(e.message) if $VERBOSE
|
|
7
9
|
end
|
|
8
10
|
|
|
11
|
+
begin
|
|
12
|
+
require 'legion/extensions/llm/inventory/scoped_refresher'
|
|
13
|
+
rescue LoadError => e
|
|
14
|
+
warn(e.message) if $VERBOSE
|
|
15
|
+
end
|
|
16
|
+
|
|
9
17
|
return unless defined?(Legion::Extensions::Actors::Every)
|
|
10
18
|
|
|
11
19
|
module Legion
|
|
@@ -13,10 +21,16 @@ module Legion
|
|
|
13
21
|
module Llm
|
|
14
22
|
module AzureFoundry
|
|
15
23
|
module Actor
|
|
16
|
-
class DiscoveryRefresh < Legion::Extensions::Actors::Every # rubocop:disable Style/Documentation
|
|
24
|
+
class DiscoveryRefresh < Legion::Extensions::Actors::Every # rubocop:disable Style/Documentation,Metrics/ClassLength
|
|
17
25
|
include Legion::Logging::Helper
|
|
18
26
|
|
|
19
|
-
|
|
27
|
+
if defined?(Legion::Extensions::Llm::Inventory::ScopedRefresher)
|
|
28
|
+
include Legion::Extensions::Llm::Inventory::ScopedRefresher
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
EMBED_TYPES = %i[embed embedding].freeze
|
|
32
|
+
|
|
33
|
+
def self.every_seconds = 3600
|
|
20
34
|
|
|
21
35
|
def runner_class = self.class
|
|
22
36
|
def runner_function = 'manual'
|
|
@@ -26,13 +40,15 @@ module Legion
|
|
|
26
40
|
def generate_task? = false
|
|
27
41
|
|
|
28
42
|
def time
|
|
29
|
-
return
|
|
43
|
+
return self.class.every_seconds unless defined?(Legion::Settings)
|
|
30
44
|
|
|
31
|
-
Legion::Settings.dig(:extensions, :llm, :azure_foundry, :discovery_interval) ||
|
|
45
|
+
Legion::Settings.dig(:extensions, :llm, :azure_foundry, :discovery_interval) || self.class.every_seconds
|
|
32
46
|
end
|
|
33
47
|
|
|
34
|
-
def manual
|
|
48
|
+
def manual # rubocop:disable Metrics/CyclomaticComplexity
|
|
35
49
|
log.debug('[azure_foundry][discovery_refresh] refreshing model list')
|
|
50
|
+
tick if respond_to?(:tick)
|
|
51
|
+
|
|
36
52
|
return unless defined?(Legion::LLM::Discovery)
|
|
37
53
|
|
|
38
54
|
Legion::LLM::Discovery.refresh_discovered_models!(provider: :azure_foundry)
|
|
@@ -46,6 +62,109 @@ module Legion
|
|
|
46
62
|
rescue StandardError => e
|
|
47
63
|
handle_exception(e, level: :warn, handled: true, operation: 'azure_foundry.actor.discovery_refresh')
|
|
48
64
|
end
|
|
65
|
+
|
|
66
|
+
def scope_key(**)
|
|
67
|
+
{ provider: :azure_foundry }
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def compute_lanes_for_scope(**)
|
|
71
|
+
return [] unless defined?(Legion::LLM::Call::Registry)
|
|
72
|
+
|
|
73
|
+
instances = Legion::LLM::Call::Registry.all_instances.select do |e|
|
|
74
|
+
(e[:provider] || '').to_sym == :azure_foundry
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
lanes = []
|
|
78
|
+
instances.each { |entry| collect_instance_lanes(entry, lanes) }
|
|
79
|
+
lanes
|
|
80
|
+
rescue StandardError => e
|
|
81
|
+
handle_exception(e, level: :warn, handled: true,
|
|
82
|
+
operation: 'azure_foundry.compute_lanes_for_scope')
|
|
83
|
+
[]
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def credential_hash(**)
|
|
87
|
+
settings = Legion::Settings.dig(:extensions, :llm, :azure_foundry) || {}
|
|
88
|
+
::Digest::SHA256.hexdigest(settings[:api_key].to_s + settings[:instances].to_s)[0, 16]
|
|
89
|
+
rescue StandardError
|
|
90
|
+
'unknown'
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
private
|
|
94
|
+
|
|
95
|
+
def collect_instance_lanes(instance_entry, lanes)
|
|
96
|
+
adapter = instance_entry[:adapter]
|
|
97
|
+
return unless adapter.respond_to?(:discover_offerings)
|
|
98
|
+
|
|
99
|
+
Array(adapter.discover_offerings(live: true)).each do |offering|
|
|
100
|
+
build_and_append_lanes(offering, instance_entry, lanes)
|
|
101
|
+
end
|
|
102
|
+
rescue StandardError => e
|
|
103
|
+
handle_exception(e, level: :warn, handled: true,
|
|
104
|
+
operation: 'azure_foundry.compute_lanes_for_scope.instance')
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def build_and_append_lanes(offering, instance_entry, lanes)
|
|
108
|
+
raw = offering.respond_to?(:to_h) ? offering.to_h : offering
|
|
109
|
+
return unless raw.is_a?(Hash)
|
|
110
|
+
|
|
111
|
+
lane = build_lane(raw, instance_entry)
|
|
112
|
+
lanes << lane
|
|
113
|
+
lanes << lane.merge(id: fleet_id_for(lane), tier: :fleet) if fleet_enabled? && lane[:type] == :inference
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def build_lane(raw, instance_entry) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
|
|
117
|
+
model = raw[:model] || raw['model']
|
|
118
|
+
instance_id = raw[:instance_id] || raw['instance_id'] ||
|
|
119
|
+
instance_entry[:instance] || instance_entry[:instance_id] ||
|
|
120
|
+
instance_entry[:id] || :default
|
|
121
|
+
pf = raw[:provider_family] || raw['provider_family'] || :azure_foundry
|
|
122
|
+
type = resolve_type(raw)
|
|
123
|
+
tier = (raw[:tier] || raw['tier'] || :cloud).to_sym
|
|
124
|
+
lane_id = compose_lane_id(tier: tier, provider_family: pf, instance_id: instance_id,
|
|
125
|
+
type: type, model: model)
|
|
126
|
+
|
|
127
|
+
{
|
|
128
|
+
id: lane_id,
|
|
129
|
+
tier: tier,
|
|
130
|
+
provider_family: pf,
|
|
131
|
+
instance_id: instance_id,
|
|
132
|
+
model: model,
|
|
133
|
+
canonical_model_alias: raw[:canonical_model_alias] || raw['canonical_model_alias'],
|
|
134
|
+
type: type,
|
|
135
|
+
capabilities: normalize_capabilities(raw[:capabilities] || raw['capabilities'] || []),
|
|
136
|
+
limits: raw[:limits] || raw['limits'] || {},
|
|
137
|
+
enabled: raw.fetch(:enabled, raw.fetch('enabled', true)),
|
|
138
|
+
cost: raw[:cost] || raw['cost'] || {}
|
|
139
|
+
}
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def resolve_type(raw)
|
|
143
|
+
val = raw[:type] || raw['type'] || raw[:usage_type] || raw['usage_type']
|
|
144
|
+
EMBED_TYPES.include?(val&.to_sym) ? :embedding : :inference
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def normalize_capabilities(raw)
|
|
148
|
+
if defined?(Legion::Extensions::Llm::Inventory::Capabilities)
|
|
149
|
+
Legion::Extensions::Llm::Inventory::Capabilities.normalize(raw)
|
|
150
|
+
else
|
|
151
|
+
Array(raw)
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def compose_lane_id(**fields)
|
|
156
|
+
Legion::Extensions::Llm::Inventory::ScopedRefresher.compose_id(fields)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def fleet_id_for(lane)
|
|
160
|
+
compose_lane_id(tier: :fleet, provider_family: lane[:provider_family],
|
|
161
|
+
instance_id: lane[:instance_id], type: lane[:type], model: lane[:model])
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def fleet_enabled?
|
|
165
|
+
settings = Legion::Settings.dig(:extensions, :llm, :azure_foundry) || {}
|
|
166
|
+
settings[:fleet]&.dig(:dispatch, :enabled)
|
|
167
|
+
end
|
|
49
168
|
end
|
|
50
169
|
end
|
|
51
170
|
end
|
|
@@ -121,6 +121,10 @@ module Legion
|
|
|
121
121
|
|
|
122
122
|
def stream_usage_supported? = true
|
|
123
123
|
|
|
124
|
+
def settings
|
|
125
|
+
AzureFoundry.default_settings.dig(:instances, :default)
|
|
126
|
+
end
|
|
127
|
+
|
|
124
128
|
def api_base
|
|
125
129
|
endpoint = config.azure_foundry_endpoint.to_s.sub(%r{/*\z}, '')
|
|
126
130
|
return "#{endpoint}/openai/v1" if surface == OPENAI_V1_SURFACE && !endpoint.end_with?('/openai/v1')
|
|
@@ -139,33 +143,21 @@ module Legion
|
|
|
139
143
|
def completion_url = path_for('chat/completions')
|
|
140
144
|
def chat_url = completion_url
|
|
141
145
|
def stream_url = completion_url
|
|
142
|
-
def models_url = path_for('info')
|
|
146
|
+
def models_url = surface == MODEL_INFERENCE_SURFACE ? path_for('info') : path_for('models')
|
|
143
147
|
def embedding_url(**) = path_for('embeddings')
|
|
144
148
|
def health_url = models_url
|
|
145
149
|
|
|
146
|
-
def
|
|
147
|
-
log.info { "discovering offerings live=#{live} from #{api_base}" }
|
|
148
|
-
offerings = filter_offerings(allowed_offerings, **filters)
|
|
149
|
-
return offerings unless live
|
|
150
|
-
|
|
151
|
-
offerings.map do |offering|
|
|
152
|
-
with_live_metadata(offering)
|
|
153
|
-
rescue StandardError => e
|
|
154
|
-
handle_exception(e, level: :warn, handled: true, operation: 'azure_foundry.discover_offerings')
|
|
155
|
-
with_health(offering, ready: false, checked: true, error: e)
|
|
156
|
-
end
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
def offering_for(model:, model_family: nil, canonical_model_alias: nil, instance_id: :default, # rubocop:disable Metrics/ParameterLists
|
|
150
|
+
def offering_for(model:, model_family: nil, canonical_model_alias: nil, instance_id: nil, # rubocop:disable Metrics/ParameterLists, Metrics/AbcSize
|
|
160
151
|
usage_type: nil, **metadata)
|
|
161
152
|
deployment = self.class.deployment_config(model, config:)
|
|
162
153
|
model_id = self.class.resolve_model_id(model, config:)
|
|
163
154
|
configured_family = value_for(deployment, :model_family)
|
|
164
155
|
configured_alias = value_for(deployment, :canonical_model_alias)
|
|
156
|
+
resolved_instance_id = instance_id || provider_instance_id
|
|
165
157
|
|
|
166
158
|
build_offering(
|
|
167
159
|
model: model_id,
|
|
168
|
-
instance_id:
|
|
160
|
+
instance_id: resolved_instance_id,
|
|
169
161
|
model_family: normalize_family(model_family || configured_family || infer_model_family(model_id)),
|
|
170
162
|
canonical_model_alias: canonical_model_alias || configured_alias,
|
|
171
163
|
usage_type: usage_type || value_for(deployment, :usage_type) || usage_type_for(model_id),
|
|
@@ -179,10 +171,12 @@ module Legion
|
|
|
179
171
|
return baseline.merge(checked: false) unless live
|
|
180
172
|
|
|
181
173
|
response = connection.get(health_url)
|
|
182
|
-
baseline.merge(checked: true,
|
|
174
|
+
baseline.merge(checked: true, ready: true, status: 'healthy', circuit_state: 'closed',
|
|
175
|
+
raw: response.body)
|
|
183
176
|
rescue StandardError => e
|
|
184
177
|
handle_exception(e, level: :warn, handled: true, operation: 'azure_foundry.health')
|
|
185
|
-
baseline.merge(checked: true, ready: false,
|
|
178
|
+
baseline.merge(checked: true, ready: false, status: 'unhealthy', circuit_state: 'open',
|
|
179
|
+
error: e.class.name, message: e.message)
|
|
186
180
|
end
|
|
187
181
|
|
|
188
182
|
def readiness(live: false)
|
|
@@ -258,11 +252,15 @@ module Legion
|
|
|
258
252
|
end
|
|
259
253
|
|
|
260
254
|
def health_baseline(live)
|
|
255
|
+
ready = configured?
|
|
261
256
|
{
|
|
262
257
|
provider: :azure_foundry,
|
|
263
|
-
|
|
264
|
-
|
|
258
|
+
instance_id: provider_instance_id,
|
|
259
|
+
configured: ready,
|
|
260
|
+
ready: ready,
|
|
265
261
|
live: live,
|
|
262
|
+
status: ready ? 'healthy' : 'unhealthy',
|
|
263
|
+
circuit_state: ready ? 'closed' : 'open',
|
|
266
264
|
api_base: api_base,
|
|
267
265
|
surface: surface
|
|
268
266
|
}
|
|
@@ -287,10 +285,14 @@ module Legion
|
|
|
287
285
|
config.azure_foundry_api_version || DEFAULT_API_VERSION
|
|
288
286
|
end
|
|
289
287
|
|
|
288
|
+
# Paths MUST be relative (no leading slash). Faraday builds the
|
|
289
|
+
# connection with api_base as the base URL — on the openai_v1 surface
|
|
290
|
+
# that base carries the /openai/v1 path, and a leading-slash path would
|
|
291
|
+
# be treated as absolute and drop it, 404ing discovery and chat.
|
|
290
292
|
def path_for(path)
|
|
291
|
-
prefix = surface == MODEL_INFERENCE_SURFACE ? '/
|
|
293
|
+
prefix = surface == MODEL_INFERENCE_SURFACE ? 'models/' : ''
|
|
292
294
|
suffix = surface == MODEL_INFERENCE_SURFACE ? "?api-version=#{api_version}" : ''
|
|
293
|
-
"#{prefix}
|
|
295
|
+
"#{prefix}#{path}#{suffix}"
|
|
294
296
|
end
|
|
295
297
|
|
|
296
298
|
def bearer_header
|
|
@@ -298,6 +300,20 @@ module Legion
|
|
|
298
300
|
token ? "Bearer #{token}" : nil
|
|
299
301
|
end
|
|
300
302
|
|
|
303
|
+
def discover_offerings(live: false, raise_on_unreachable: false, **filters)
|
|
304
|
+
offerings = allowed_offerings
|
|
305
|
+
return filter_offerings(offerings, **filters) unless live
|
|
306
|
+
|
|
307
|
+
resolved = offerings.map { |offering| with_live_metadata(offering) }
|
|
308
|
+
filter_offerings(resolved, **filters)
|
|
309
|
+
rescue Faraday::ConnectionFailed, Faraday::TimeoutError => e
|
|
310
|
+
log.warn("[#{slug}] instance=#{provider_instance_id} unreachable: #{e.message}")
|
|
311
|
+
raise if raise_on_unreachable
|
|
312
|
+
|
|
313
|
+
[]
|
|
314
|
+
end
|
|
315
|
+
public :discover_offerings
|
|
316
|
+
|
|
301
317
|
def configured_deployments
|
|
302
318
|
self.class.normalize_deployments(config.azure_foundry_deployments)
|
|
303
319
|
end
|
|
@@ -315,16 +331,34 @@ module Legion
|
|
|
315
331
|
end
|
|
316
332
|
|
|
317
333
|
def offering_from_config(deployment)
|
|
318
|
-
deployment_name = value_for(deployment, :deployment) || value_for(deployment, :model)
|
|
319
|
-
return nil if deployment_name.to_s.empty?
|
|
320
|
-
|
|
321
334
|
offering_for(
|
|
322
|
-
model:
|
|
335
|
+
model: value_for(deployment, :deployment) || value_for(deployment, :model),
|
|
323
336
|
model_family: value_for(deployment, :model_family),
|
|
324
337
|
canonical_model_alias: value_for(deployment, :canonical_model_alias),
|
|
325
|
-
instance_id:
|
|
326
|
-
usage_type: value_for(deployment, :usage_type),
|
|
327
|
-
|
|
338
|
+
instance_id: provider_instance_id,
|
|
339
|
+
usage_type: value_for(deployment, :usage_type) || :inference,
|
|
340
|
+
metadata: deployment_metadata(deployment)
|
|
341
|
+
)
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
def offering_from_model(model_info, _health: nil) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
345
|
+
model_id = model_info.respond_to?(:id) ? model_info.id : model_info['id']
|
|
346
|
+
name = model_info.respond_to?(:name) ? model_info.name : model_info['name'] || model_id
|
|
347
|
+
family = model_info.respond_to?(:family) ? model_info.family : model_info['model_family']
|
|
348
|
+
usage = model_info.respond_to?(:embedding?) && model_info.embedding? ? :embedding : :inference
|
|
349
|
+
meta = if model_info.respond_to?(:metadata)
|
|
350
|
+
model_info.metadata
|
|
351
|
+
else
|
|
352
|
+
model_info.is_a?(Hash) ? model_info : {}
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
offering_for(
|
|
356
|
+
model: model_id,
|
|
357
|
+
model_family: family,
|
|
358
|
+
canonical_model_alias: name,
|
|
359
|
+
instance_id: provider_instance_id,
|
|
360
|
+
usage_type: usage,
|
|
361
|
+
metadata: meta
|
|
328
362
|
)
|
|
329
363
|
end
|
|
330
364
|
|
|
@@ -376,7 +410,7 @@ module Legion
|
|
|
376
410
|
|
|
377
411
|
def resolve_capability_policy(model, usage_type)
|
|
378
412
|
if usage_type.to_sym == :embedding
|
|
379
|
-
return { capabilities: %i[
|
|
413
|
+
return { capabilities: %i[embedding], sources: { embedding: { value: true, source: :model_metadata } } }
|
|
380
414
|
end
|
|
381
415
|
|
|
382
416
|
real_caps = real_capabilities_for(model)
|
|
@@ -420,7 +454,7 @@ module Legion
|
|
|
420
454
|
|
|
421
455
|
cfg.except(:instances, 'instances')
|
|
422
456
|
rescue StandardError => e
|
|
423
|
-
handle_exception(e, level: :
|
|
457
|
+
handle_exception(e, level: :warn, handled: true, operation: 'azure_foundry.provider_level_config')
|
|
424
458
|
{}
|
|
425
459
|
end
|
|
426
460
|
|
|
@@ -66,7 +66,7 @@ module Legion
|
|
|
66
66
|
cfg['api_base']
|
|
67
67
|
return if endpoint.nil? || endpoint.to_s.strip.empty?
|
|
68
68
|
|
|
69
|
-
instances[:settings] = normalize_instance_config(cfg).merge(tier: :cloud)
|
|
69
|
+
instances[:settings] = normalize_instance_config(cfg).merge(tier: cfg[:tier] || cfg['tier'] || :cloud)
|
|
70
70
|
end
|
|
71
71
|
|
|
72
72
|
def self.discover_named_instances(instances)
|
|
@@ -86,7 +86,8 @@ module Legion
|
|
|
86
86
|
config[:api_base] || config['api_base']
|
|
87
87
|
return if endpoint.nil? || endpoint.to_s.strip.empty?
|
|
88
88
|
|
|
89
|
-
instances[name.to_sym] =
|
|
89
|
+
instances[name.to_sym] =
|
|
90
|
+
normalize_instance_config(config).merge(tier: config[:tier] || config['tier'] || :cloud)
|
|
90
91
|
end
|
|
91
92
|
|
|
92
93
|
def self.normalize_instance_config(config) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: lex-llm-azure-foundry
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.14
|
|
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: Azure AI Foundry and Azure OpenAI hosted provider integration for LegionIO
|
|
83
83
|
LLM routing.
|
|
84
84
|
email:
|