Module: Legion::Extensions::Llm::AzureFoundry::Runners::Discovery
- Extended by:
- Helpers::OfferingEvidence, Discovery
- Includes:
- Discovery::Pipeline
- Included in:
- Discovery
- Defined in:
- lib/legion/extensions/llm/azure_foundry/runners/discovery.rb
Overview
Azure AI Foundry discovery runner: ONLY the Azure Foundry-specific work. The generic reconcile / claim / activate / probe (cadence + reactive) / replace / weight-publication / health-display pipeline is mixed in from the shared Discovery::Pipeline. Weight is NOT computed here — the shared WeightReconciler recomputes it from live settings at publish.
The catalog is NOT the OpenAI-compatible GET /v1/models shape: each
instance serves a surface — models/info?api-version=
Instance Method Summary collapse
-
#apply_auth_headers(faraday:, instance_cfg:) ⇒ Object
Azure Foundry authenticates with an api-key header and/or a bearer Authorization header — not a plain bearer only.
- #auth_token(instance_cfg:) ⇒ Object
- #build_callable(instance_cfg:) ⇒ Object
-
#build_offering_draft(instance_cfg:, instance_key:, model_id:, model_data:) ⇒ Object
── Offering draft (evidence + metadata; NO weight) ──────────────.
-
#catalog_base_url(instance_cfg:) ⇒ Object
── Azure Foundry instance-config keys / connection ────────────── The normalized instance config (AzureFoundry.discover_instances) carries azure_foundry_endpoint / azure_foundry_api_key / azure_foundry_bearer_token / azure_foundry_surface / azure_foundry_api_version; the pipeline's catalog_base_url and auth_token read the standard keys, so override to these.
-
#catalog_body(response) ⇒ Object
Catalog responses arrive as raw strings (this connection has no JSON middleware) — parse through the shared helper.
-
#catalog_path(instance_cfg:) ⇒ Object
── Catalog fetch / readiness (same non-inference GET) ─────────── The model catalog discovery path, per surface.
-
#check_health(instance_cfg:) ⇒ Object
Readiness is a non-inference GET of the model catalog endpoint (models/info on the model-inference surface, models on the OpenAI-compatible surface), never a chat/embed call.
-
#derive_physical_id(instance_cfg:) ⇒ Object
── Secondary physical id (dedup/diagnostics only) ─────────────── endpoint host:port, or host:port/ak:
when an api key is present. - #extract_host_port(url:) ⇒ Object
-
#fetch_raw_models(instance_cfg:) ⇒ Object
A failed catalog fetch is a CatalogFetchFailure (the pipeline keeps the last good snapshot), never a nil.
- #model_id_from(model_data) ⇒ Object
-
#provider_family ⇒ Object
The derived family would be :azurefoundry (lowercased module name); the registered family everywhere (Publisher, InstanceKey, WeightReconciler) is :azure_foundry.
Instance Method Details
#apply_auth_headers(faraday:, instance_cfg:) ⇒ Object
Azure Foundry authenticates with an api-key header and/or a bearer Authorization header — not a plain bearer only.
65 66 67 68 69 70 71 |
# File 'lib/legion/extensions/llm/azure_foundry/runners/discovery.rb', line 65 def apply_auth_headers(faraday:, instance_cfg:) api_key = instance_cfg[:azure_foundry_api_key] faraday.headers['api-key'] = api_key if credential_string?(api_key) bearer_token = instance_cfg[:azure_foundry_bearer_token] faraday.headers['Authorization'] = "Bearer #{bearer_token}" if credential_string?(bearer_token) end |
#auth_token(instance_cfg:) ⇒ Object
58 59 60 61 |
# File 'lib/legion/extensions/llm/azure_foundry/runners/discovery.rb', line 58 def auth_token(instance_cfg:) token = instance_cfg[:azure_foundry_api_key] token if credential_string?(token) end |
#build_callable(instance_cfg:) ⇒ Object
128 129 130 |
# File 'lib/legion/extensions/llm/azure_foundry/runners/discovery.rb', line 128 def build_callable(instance_cfg:) Legion::Extensions::Llm::AzureFoundry::Helpers::Callable.new(instance_cfg: instance_cfg, logger: log) end |
#build_offering_draft(instance_cfg:, instance_key:, model_id:, model_data:) ⇒ Object
── Offering draft (evidence + metadata; NO weight) ──────────────
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 |
# File 'lib/legion/extensions/llm/azure_foundry/runners/discovery.rb', line 159 def build_offering_draft(instance_cfg:, instance_key:, model_id:, model_data:) tier = (instance_cfg[:tier] || :cloud).to_sym = (model_id, model_data) base_name = Legion::Extensions::Llm::AzureFoundry::ModelCatalogParser.base_model_name_for(model_data) Legion::Extensions::Llm::Inventory::OfferingDraft.new( provider_native_key: model_id, model: model_id, tier: tier, operation_evidence: build_operation_evidence(embed_supported: ), capability_evidence: build_capability_evidence(entry: model_data, embed_supported: ), context_evidence: build_context_evidence(entry: model_data, instance_cfg: instance_cfg), max_output_evidence: build_max_output_evidence(entry: model_data, instance_cfg: instance_cfg), embedding_dimensions_evidence: absent_value_evidence, model_revision_evidence: absent_value_evidence, tokenizer_evidence: absent_value_evidence, quota_domains: build_quota_domains(model_id: model_id), metadata: (model_id: model_id, base_name: base_name, instance_key: instance_key).freeze, publication_source: :provider_catalog ) end |
#catalog_base_url(instance_cfg:) ⇒ Object
── Azure Foundry instance-config keys / connection ────────────── The normalized instance config (AzureFoundry.discover_instances) carries azure_foundry_endpoint / azure_foundry_api_key / azure_foundry_bearer_token / azure_foundry_surface / azure_foundry_api_version; the pipeline's catalog_base_url and auth_token read the standard keys, so override to these.
50 51 52 53 54 55 56 |
# File 'lib/legion/extensions/llm/azure_foundry/runners/discovery.rb', line 50 def catalog_base_url(instance_cfg:) url = instance_cfg[:azure_foundry_endpoint].to_s.sub(%r{/*\z}, '') raise ArgumentError, 'azure_foundry_endpoint is required for the connection' if url.strip.empty? return "#{url}/openai/v1" if surface_for(instance_cfg) == :openai_v1 && !url.end_with?('/openai/v1') url end |
#catalog_body(response) ⇒ Object
Catalog responses arrive as raw strings (this connection has no JSON middleware) — parse through the shared helper.
97 98 99 100 101 102 |
# File 'lib/legion/extensions/llm/azure_foundry/runners/discovery.rb', line 97 def catalog_body(response) body = response.body return Legion::JSON.parse(body, symbolize_names: false) if body.is_a?(String) && !body.strip.empty? body end |
#catalog_path(instance_cfg:) ⇒ Object
── Catalog fetch / readiness (same non-inference GET) ─────────── The model catalog discovery path, per surface. The provider's models_url and this path must agree — both derive from the surface and api-version the same way.
77 78 79 80 81 82 |
# File 'lib/legion/extensions/llm/azure_foundry/runners/discovery.rb', line 77 def catalog_path(instance_cfg:) return 'models' if surface_for(instance_cfg) == :openai_v1 version = instance_cfg[:azure_foundry_api_version] || instance_cfg[:api_version] || '2024-05-01-preview' "models/info?api-version=#{version}" end |
#check_health(instance_cfg:) ⇒ Object
Readiness is a non-inference GET of the model catalog endpoint (models/info on the model-inference surface, models on the OpenAI-compatible surface), never a chat/embed call. The catalog discovery hits the SAME endpoint through the same auth.
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/legion/extensions/llm/azure_foundry/runners/discovery.rb', line 112 def check_health(instance_cfg:) conn = build_connection(base_url: catalog_base_url(instance_cfg: instance_cfg), instance_cfg: instance_cfg, timeout: 5, open_timeout: 3) status = conn.get(catalog_path(instance_cfg: instance_cfg)).status Legion::Extensions::Llm::Inventory::ReadinessResult.new( ready: status == 200, reason: "Azure Foundry health returned #{status}", metadata: { status: status, endpoint: instance_cfg[:azure_foundry_endpoint].to_s } ) rescue StandardError => e handle_exception(e, level: :warn, operation: 'azure_foundry.runner.discovery.health') Legion::Extensions::Llm::Inventory::ReadinessResult.new( ready: false, reason: "Azure Foundry health error: #{e.}", metadata: { error_class: e.class.name } ) end |
#derive_physical_id(instance_cfg:) ⇒ Object
── Secondary physical id (dedup/diagnostics only) ───────────────
endpoint host:port, or host:port/ak:
136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/legion/extensions/llm/azure_foundry/runners/discovery.rb', line 136 def derive_physical_id(instance_cfg:) endpoint = instance_cfg[:azure_foundry_endpoint] raise ArgumentError, 'azure_foundry_endpoint is required to derive the physical id' unless credential_string?(endpoint) host_port = extract_host_port(url: endpoint) api_key = instance_cfg[:azure_foundry_api_key] return host_port unless credential_string?(api_key) "#{host_port}/ak:#{Legion::Extensions::Llm::CredentialSources.credential_fingerprint(api_key)}" end |
#extract_host_port(url:) ⇒ Object
148 149 150 151 152 153 154 155 156 |
# File 'lib/legion/extensions/llm/azure_foundry/runners/discovery.rb', line 148 def extract_host_port(url:) uri = URI.parse(url.to_s) host = (uri.host || 'localhost').downcase "#{host}:#{uri.port}" rescue URI::InvalidURIError => e handle_exception(e, level: :warn, operation: 'azure_foundry.runner.discovery.extract_host_port', url: url.to_s) raise end |
#fetch_raw_models(instance_cfg:) ⇒ Object
A failed catalog fetch is a CatalogFetchFailure (the pipeline keeps the last good snapshot), never a nil.
86 87 88 89 90 91 92 93 |
# File 'lib/legion/extensions/llm/azure_foundry/runners/discovery.rb', line 86 def fetch_raw_models(instance_cfg:) conn = build_connection(base_url: catalog_base_url(instance_cfg: instance_cfg), instance_cfg: instance_cfg, timeout: 10, open_timeout: 5) response = conn.get(catalog_path(instance_cfg: instance_cfg)) raise CatalogFetchFailure, "catalog fetch returned HTTP #{response.status}" unless response.status == 200 Legion::Extensions::Llm::AzureFoundry::ModelCatalogParser.model_entries(catalog_body(response)) end |
#model_id_from(model_data) ⇒ Object
104 105 106 |
# File 'lib/legion/extensions/llm/azure_foundry/runners/discovery.rb', line 104 def model_id_from(model_data) Legion::Extensions::Llm::AzureFoundry::ModelCatalogParser.model_id_for(model_data) end |
#provider_family ⇒ Object
The derived family would be :azurefoundry (lowercased module name); the registered family everywhere (Publisher, InstanceKey, WeightReconciler) is :azure_foundry.
42 |
# File 'lib/legion/extensions/llm/azure_foundry/runners/discovery.rb', line 42 def provider_family = :azure_foundry |