lex-llm-azure-foundry 0.2.10 → 0.2.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 +20 -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 +58 -28
- 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: 76e76ee4edefeb764f3d1829a900e1bf60bf9ccc598532feb0d6033680af329f
|
|
4
|
+
data.tar.gz: 778667f3720744c2b5ea38e96d52db29d22c4228f4247a55e9976fd2e1b85612
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f1facb1bad185f1b7d2429213869f637598802d078ea1bf453c670de3ff5426f56e763d0102e3b15ce78f4afb6bd36788bf7269918416191b0daa483e5ae6ca4
|
|
7
|
+
data.tar.gz: aa1a7c88250da3f1d676ef92fbb0f46522d44994e54d49707daad0ec38eb0e940341ea4f9b0661af9d117771b4fe5d3e4156a3c29d21a11b74446dd9fdbd9570
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.2.13] - 2026-06-20
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- 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`.
|
|
7
|
+
|
|
8
|
+
## [0.2.12] - 2026-06-20
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
- Align Azure Foundry instance discovery with the shared `lex-llm` contract by preserving explicit tier overrides while defaulting unconfigured instances to `:cloud`.
|
|
12
|
+
- Restore offline deployment-backed offering discovery and carry the configured provider instance id through Azure offering metadata.
|
|
13
|
+
- Normalize Azure Foundry capability and health metadata to the current shared offering contract.
|
|
14
|
+
|
|
15
|
+
## [0.2.11] - 2026-06-19
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
- Adopt `Legion::Extensions::Llm::Inventory::ScopedRefresher` mixin (lex-llm 0.6.0). Discovery
|
|
19
|
+
refresh actors now write directly to the live `Inventory` catalog via `Inventory.write_lane`.
|
|
20
|
+
- Pin `lex-llm >= 0.6.0` and `legion-llm >= 0.14.0` in gemspec.
|
|
21
|
+
- Standard `weight: 100` default added to provider instance settings schema.
|
|
22
|
+
|
|
3
23
|
## 0.2.10 - 2026-06-16
|
|
4
24
|
|
|
5
25
|
- 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')
|
|
@@ -143,29 +147,17 @@ module Legion
|
|
|
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
|
}
|
|
@@ -298,6 +296,20 @@ module Legion
|
|
|
298
296
|
token ? "Bearer #{token}" : nil
|
|
299
297
|
end
|
|
300
298
|
|
|
299
|
+
def discover_offerings(live: false, raise_on_unreachable: false, **filters)
|
|
300
|
+
offerings = allowed_offerings
|
|
301
|
+
return filter_offerings(offerings, **filters) unless live
|
|
302
|
+
|
|
303
|
+
resolved = offerings.map { |offering| with_live_metadata(offering) }
|
|
304
|
+
filter_offerings(resolved, **filters)
|
|
305
|
+
rescue Faraday::ConnectionFailed, Faraday::TimeoutError => e
|
|
306
|
+
log.warn("[#{slug}] instance=#{provider_instance_id} unreachable: #{e.message}")
|
|
307
|
+
raise if raise_on_unreachable
|
|
308
|
+
|
|
309
|
+
[]
|
|
310
|
+
end
|
|
311
|
+
public :discover_offerings
|
|
312
|
+
|
|
301
313
|
def configured_deployments
|
|
302
314
|
self.class.normalize_deployments(config.azure_foundry_deployments)
|
|
303
315
|
end
|
|
@@ -315,16 +327,34 @@ module Legion
|
|
|
315
327
|
end
|
|
316
328
|
|
|
317
329
|
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
330
|
offering_for(
|
|
322
|
-
model:
|
|
331
|
+
model: value_for(deployment, :deployment) || value_for(deployment, :model),
|
|
323
332
|
model_family: value_for(deployment, :model_family),
|
|
324
333
|
canonical_model_alias: value_for(deployment, :canonical_model_alias),
|
|
325
|
-
instance_id:
|
|
326
|
-
usage_type: value_for(deployment, :usage_type),
|
|
327
|
-
|
|
334
|
+
instance_id: provider_instance_id,
|
|
335
|
+
usage_type: value_for(deployment, :usage_type) || :inference,
|
|
336
|
+
metadata: deployment_metadata(deployment)
|
|
337
|
+
)
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
def offering_from_model(model_info, _health: nil) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
341
|
+
model_id = model_info.respond_to?(:id) ? model_info.id : model_info['id']
|
|
342
|
+
name = model_info.respond_to?(:name) ? model_info.name : model_info['name'] || model_id
|
|
343
|
+
family = model_info.respond_to?(:family) ? model_info.family : model_info['model_family']
|
|
344
|
+
usage = model_info.respond_to?(:embedding?) && model_info.embedding? ? :embedding : :inference
|
|
345
|
+
meta = if model_info.respond_to?(:metadata)
|
|
346
|
+
model_info.metadata
|
|
347
|
+
else
|
|
348
|
+
model_info.is_a?(Hash) ? model_info : {}
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
offering_for(
|
|
352
|
+
model: model_id,
|
|
353
|
+
model_family: family,
|
|
354
|
+
canonical_model_alias: name,
|
|
355
|
+
instance_id: provider_instance_id,
|
|
356
|
+
usage_type: usage,
|
|
357
|
+
metadata: meta
|
|
328
358
|
)
|
|
329
359
|
end
|
|
330
360
|
|
|
@@ -376,7 +406,7 @@ module Legion
|
|
|
376
406
|
|
|
377
407
|
def resolve_capability_policy(model, usage_type)
|
|
378
408
|
if usage_type.to_sym == :embedding
|
|
379
|
-
return { capabilities: %i[
|
|
409
|
+
return { capabilities: %i[embedding], sources: { embedding: { value: true, source: :model_metadata } } }
|
|
380
410
|
end
|
|
381
411
|
|
|
382
412
|
real_caps = real_capabilities_for(model)
|
|
@@ -420,7 +450,7 @@ module Legion
|
|
|
420
450
|
|
|
421
451
|
cfg.except(:instances, 'instances')
|
|
422
452
|
rescue StandardError => e
|
|
423
|
-
handle_exception(e, level: :
|
|
453
|
+
handle_exception(e, level: :warn, handled: true, operation: 'azure_foundry.provider_level_config')
|
|
424
454
|
{}
|
|
425
455
|
end
|
|
426
456
|
|
|
@@ -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.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: Azure AI Foundry and Azure OpenAI hosted provider integration for LegionIO
|
|
83
83
|
LLM routing.
|
|
84
84
|
email:
|