lex-llm-azure-foundry 0.2.14 → 0.2.15

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: 30c68d11d7549c672c912006d7ca6e843fbd976cd7e5e1845db580b9f86543f8
4
- data.tar.gz: 5451587d09659bd54f9f6a5d52c165f1eee58a66a2667797a65a7f2f84c9fbce
3
+ metadata.gz: e53b1d826dd7b500516b5d81d4d1502f4cc0c3edbe9453fe80a2436343fdece9
4
+ data.tar.gz: 4b9206ecc5905a2325b4a626901ea4e2cdb5166dba0c9b679a91668a584d5fd1
5
5
  SHA512:
6
- metadata.gz: 0a9509a27ea507bfa9cf0a68564cb56cafad2ca30fe8f158a2a1a33dcdb701dc3b25289ce0707a524c9488f54f12421005702b31b3bf6d2b35eb869bc79f77e8
7
- data.tar.gz: 0dd91d0a237fa15c9a6fcb32f8c77d81c15274e97fc525d08a254787e91f410449b01448d43e677f9f785343738f33e0de6a0bb07076af45dc7c2ccebbf67cf6
6
+ metadata.gz: 4b8fce48bc00ff40a0d8e04f731ee2773b0f70bf0fa4e78e212065b063b9631a5f1af639f2ed9e11ba73945f8af47e36008f9b4c62782fe82669f7b6e9e91c24
7
+ data.tar.gz: 6d1a10eb83f5d62c833c51ef3ed4499b71f0d942938cca357747fbfc4bf935a5d46be0c3a0e0f052fbe42cdfcd6d9fa32610a63967ff291ff9a6b2cb18cb0774
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.2.15] - 2026-07-09
4
+
5
+ ### Fixed
6
+ - Offerings now populate `limits[:context_window]` (and `max_output_tokens`), so the router sees real capacity for Azure lanes instead of nil/unbounded. `build_offering` previously never set `limits` — deployment config context sizes landed in `metadata` and were invisible to routing (a request could then mis-route to an Azure lane the router thought had unlimited context). `context_window` is sourced from live catalog when the endpoint reports it, else per-deployment instance config (`context_window`/`max_input_tokens`), else nil (a genuine per-instance gap — never a hardcoded guess). Azure's inference-plane endpoints (`model_inference GET /info`, `openai_v1 GET /models`) do not report per-model context length, mirroring the OpenAI/Bedrock cloud providers. `Model::Info#context_length` (models API) is populated the same way.
7
+
3
8
  ## [0.2.14] - 2026-07-03
4
9
 
5
10
  ### Fixed
@@ -15,6 +15,9 @@ module Legion
15
15
  DEFAULT_API_VERSION = '2024-05-01-preview'
16
16
  MODEL_INFERENCE_SURFACE = :model_inference
17
17
  OPENAI_V1_SURFACE = :openai_v1
18
+ # Keys a live model catalog might use to report context length. Azure's own
19
+ # endpoints rarely do (see deployment_limits), so this is a best-effort read.
20
+ CATALOG_CONTEXT_KEYS = %i[context_window max_input_tokens context_length].freeze
18
21
 
19
22
  class << self
20
23
  def slug = 'azure_foundry'
@@ -161,7 +164,8 @@ module Legion
161
164
  model_family: normalize_family(model_family || configured_family || infer_model_family(model_id)),
162
165
  canonical_model_alias: canonical_model_alias || configured_alias,
163
166
  usage_type: usage_type || value_for(deployment, :usage_type) || usage_type_for(model_id),
164
- metadata: metadata.merge(deployment_metadata(deployment))
167
+ metadata: metadata.merge(deployment_metadata(deployment)),
168
+ limits: deployment_limits(deployment)
165
169
  )
166
170
  end
167
171
 
@@ -275,6 +279,7 @@ module Legion
275
279
  provider: :azure_foundry,
276
280
  family: offering.metadata[:model_family],
277
281
  capabilities: capabilities,
282
+ context_length: offering.context_window,
278
283
  modalities_input: modalities[:input],
279
284
  modalities_output: modalities[:output],
280
285
  metadata: offering.to_h
@@ -362,7 +367,8 @@ module Legion
362
367
  )
363
368
  end
364
369
 
365
- def build_offering(model:, model_family:, usage_type:, instance_id:, canonical_model_alias:, metadata:) # rubocop:disable Metrics/ParameterLists
370
+ def build_offering(model:, model_family:, usage_type:, instance_id:, canonical_model_alias:, # rubocop:disable Metrics/ParameterLists
371
+ metadata:, limits: {})
366
372
  policy = resolve_capability_policy(model, usage_type)
367
373
  Legion::Extensions::Llm::Routing::ModelOffering.new(
368
374
  provider_family: :azure_foundry,
@@ -373,6 +379,7 @@ module Legion
373
379
  usage_type: usage_type.to_sym,
374
380
  capabilities: policy[:capabilities],
375
381
  capability_sources: policy[:sources],
382
+ limits: limits,
376
383
  metadata: metadata.merge(
377
384
  model_family: model_family,
378
385
  canonical_model_alias: canonical_model_alias,
@@ -384,14 +391,29 @@ module Legion
384
391
  def with_live_metadata(offering)
385
392
  response = connection.get(models_url)
386
393
  metadata = offering.metadata.merge(model_info: response.body)
387
- with_health(offering, ready: true, checked: true, metadata:)
394
+ # Prefer a context_window the live catalog actually reports; fall back to
395
+ # whatever the deployment config already resolved (Azure endpoints usually
396
+ # omit context length, so config remains authoritative).
397
+ limits = offering.to_h[:limits].to_h
398
+ catalog_window = catalog_context_window(response.body)
399
+ limits = limits.merge(context_window: catalog_window) if catalog_window
400
+ with_health(offering, ready: true, checked: true, metadata:, limits:)
388
401
  end
389
402
 
390
- def with_health(offering, ready:, checked:, error: nil, metadata: offering.metadata)
403
+ def catalog_context_window(body)
404
+ return nil unless body.is_a?(Hash)
405
+
406
+ value = CATALOG_CONTEXT_KEYS.filter_map { |key| body[key] || body[key.to_s] }.first
407
+ value&.to_i
408
+ end
409
+
410
+ def with_health(offering, ready:, checked:, error: nil, metadata: offering.metadata, limits: nil) # rubocop:disable Metrics/ParameterLists
391
411
  health = { ready: ready, checked: checked }
392
412
  health = health.merge(error: error.class.name, message: error.message) if error
393
413
 
394
- Legion::Extensions::Llm::Routing::ModelOffering.new(offering.to_h.merge(health:, metadata:))
414
+ data = offering.to_h.merge(health:, metadata:)
415
+ data[:limits] = limits if limits
416
+ Legion::Extensions::Llm::Routing::ModelOffering.new(data)
395
417
  end
396
418
 
397
419
  def filter_offerings(offerings, model_family: nil, usage_type: nil, **)
@@ -402,6 +424,24 @@ module Legion
402
424
  end
403
425
  end
404
426
 
427
+ # Azure's inference-plane endpoints do NOT report per-model context length
428
+ # (model_inference GET /info returns only model_name/model_type/
429
+ # model_provider_name; the openai_v1 GET /models is an OpenAI-style
430
+ # id/created/owned_by list). So context_window is sourced from the
431
+ # per-deployment instance config (keys :context_window / :max_input_tokens);
432
+ # live discovery (with_live_metadata) can override it when a catalog entry
433
+ # actually carries it. Absent both, the window is nil — a per-instance gap,
434
+ # never a hardcoded guess.
435
+ def deployment_limits(deployment)
436
+ return {} unless deployment
437
+
438
+ context_window = value_for(deployment, :context_window) || value_for(deployment, :max_input_tokens)
439
+ {
440
+ context_window: context_window&.to_i,
441
+ max_output_tokens: value_for(deployment, :max_output_tokens)&.to_i
442
+ }.compact
443
+ end
444
+
405
445
  def deployment_metadata(deployment)
406
446
  return {} unless deployment
407
447
 
@@ -4,7 +4,7 @@ module Legion
4
4
  module Extensions
5
5
  module Llm
6
6
  module AzureFoundry
7
- VERSION = '0.2.14'
7
+ VERSION = '0.2.15'
8
8
  end
9
9
  end
10
10
  end
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.14
4
+ version: 0.2.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - LegionIO