Class: Legion::Extensions::Llm::AzureFoundry::Provider
- Inherits:
-
Provider
- Object
- Provider
- Legion::Extensions::Llm::AzureFoundry::Provider
- Includes:
- Provider::OpenAICompatible
- Defined in:
- lib/legion/extensions/llm/azure_foundry/provider.rb
Overview
Azure AI Foundry and Azure OpenAI hosted provider surface.
Defined Under Namespace
Modules: Capabilities
Constant Summary collapse
- DEFAULT_API_VERSION =
'2024-05-01-preview'- MODEL_INFERENCE_SURFACE =
:model_inference- OPENAI_V1_SURFACE =
:openai_v1
Class Attribute Summary collapse
Class Method Summary collapse
- .capabilities ⇒ Object
- .configuration_options ⇒ Object
- .configuration_requirements ⇒ Object
- .deployment_config(model_id, config:) ⇒ Object
- .normalize_deployments(deployments) ⇒ Object
- .resolve_model_id(model_id, config: nil) ⇒ Object
- .slug ⇒ Object
Instance Method Summary collapse
- #api_base ⇒ Object
-
#chat(messages, model:, temperature: nil, max_tokens: nil, tools: {}, tool_prefs: nil, params: {}) ⇒ Object
rubocop:disable Metrics/ParameterLists.
- #chat_url ⇒ Object
- #completion_url ⇒ Object
- #count_tokens(messages, model:) ⇒ Object
- #discover_offerings(live: false, **filters) ⇒ Object
- #embed(text, model:, dimensions: nil, input_type: nil) ⇒ Object
- #embedding_url ⇒ Object
- #headers ⇒ Object
- #health(live: false) ⇒ Object
- #health_url ⇒ Object
- #list_models ⇒ Object
- #models_url ⇒ Object
-
#offering_for(model:, model_family: nil, canonical_model_alias: nil, instance_id: :default, usage_type: nil, **metadata) ⇒ Object
rubocop:disable Metrics/ParameterLists.
- #readiness(live: false) ⇒ Object
-
#stream(messages, model:, temperature: nil, max_tokens: nil, tools: {}, tool_prefs: nil, params: {}) ⇒ Object
rubocop:disable Metrics/ParameterLists.
- #stream_url ⇒ Object
Class Attribute Details
.registry_publisher ⇒ Object
38 39 40 |
# File 'lib/legion/extensions/llm/azure_foundry/provider.rb', line 38 def registry_publisher @registry_publisher ||= RegistryPublisher.new end |
Class Method Details
.capabilities ⇒ Object
36 |
# File 'lib/legion/extensions/llm/azure_foundry/provider.rb', line 36 def capabilities = Capabilities |
.configuration_options ⇒ Object
25 26 27 28 29 30 31 32 33 34 |
# File 'lib/legion/extensions/llm/azure_foundry/provider.rb', line 25 def %i[ azure_foundry_endpoint azure_foundry_api_key azure_foundry_bearer_token azure_foundry_api_version azure_foundry_surface azure_foundry_deployments ] end |
.configuration_requirements ⇒ Object
23 |
# File 'lib/legion/extensions/llm/azure_foundry/provider.rb', line 23 def configuration_requirements = %i[azure_foundry_endpoint] |
.deployment_config(model_id, config:) ⇒ Object
47 48 49 50 51 52 53 54 |
# File 'lib/legion/extensions/llm/azure_foundry/provider.rb', line 47 def deployment_config(model_id, config:) deployments = config&.azure_foundry_deployments entries = normalize_deployments(deployments) entries.find do |entry| [value_for(entry, :deployment), value_for(entry, :model), value_for(entry, :canonical_model_alias)] .compact.map(&:to_s).include?(model_id.to_s) end end |
.normalize_deployments(deployments) ⇒ Object
56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/legion/extensions/llm/azure_foundry/provider.rb', line 56 def normalize_deployments(deployments) case deployments when Hash deployments.map do |name, | value = .to_h value[:deployment] ||= name value end else Array(deployments).map { |deployment| normalize_deployment_entry(deployment) } end end |
.resolve_model_id(model_id, config: nil) ⇒ Object
42 43 44 45 |
# File 'lib/legion/extensions/llm/azure_foundry/provider.rb', line 42 def resolve_model_id(model_id, config: nil) deployment = deployment_config(model_id, config:) value_for(deployment, :deployment) || value_for(deployment, :model) || model_id.to_s end |
.slug ⇒ Object
22 |
# File 'lib/legion/extensions/llm/azure_foundry/provider.rb', line 22 def slug = 'azure_foundry' |
Instance Method Details
#api_base ⇒ Object
122 123 124 125 126 127 128 |
# File 'lib/legion/extensions/llm/azure_foundry/provider.rb', line 122 def api_base endpoint = config.azure_foundry_endpoint.to_s.sub(%r{/*\z}, '') return "#{endpoint}/openai/v1" if surface == OPENAI_V1_SURFACE && !endpoint.end_with?('/openai/v1') return endpoint.delete_suffix('/models') if surface == MODEL_INFERENCE_SURFACE endpoint end |
#chat(messages, model:, temperature: nil, max_tokens: nil, tools: {}, tool_prefs: nil, params: {}) ⇒ Object
rubocop:disable Metrics/ParameterLists
201 202 203 |
# File 'lib/legion/extensions/llm/azure_foundry/provider.rb', line 201 def chat(, model:, temperature: nil, max_tokens: nil, tools: {}, tool_prefs: nil, params: {}) # rubocop:disable Metrics/ParameterLists complete(, tools:, temperature:, model: model_info(model, max_tokens:), params:, tool_prefs:) end |
#chat_url ⇒ Object
138 |
# File 'lib/legion/extensions/llm/azure_foundry/provider.rb', line 138 def chat_url = completion_url |
#completion_url ⇒ Object
137 |
# File 'lib/legion/extensions/llm/azure_foundry/provider.rb', line 137 def completion_url = path_for('chat/completions') |
#count_tokens(messages, model:) ⇒ Object
216 217 218 219 220 221 222 223 224 |
# File 'lib/legion/extensions/llm/azure_foundry/provider.rb', line 216 def count_tokens(, model:, **) { provider_family: :azure_foundry, model: model_id(model), supported: false, reason: 'Azure AI Foundry REST docs do not define a portable token-counting endpoint for this surface.', estimated_input_characters: .sum { || .content.to_s.length } } end |
#discover_offerings(live: false, **filters) ⇒ Object
144 145 146 147 148 149 150 151 152 153 |
# File 'lib/legion/extensions/llm/azure_foundry/provider.rb', line 144 def discover_offerings(live: false, **filters) offerings = configured_deployments.filter_map { |deployment| offering_from_config(deployment) } return filter_offerings(offerings, **filters) unless live filter_offerings(offerings, **filters).map do |offering| (offering) rescue StandardError => e with_health(offering, ready: false, checked: true, error: e) end end |
#embed(text, model:, dimensions: nil, input_type: nil) ⇒ Object
209 210 211 212 213 214 |
# File 'lib/legion/extensions/llm/azure_foundry/provider.rb', line 209 def (text, model:, dimensions: nil, input_type: nil) payload = (text, model: model_id(model), dimensions:) payload[:input_type] = input_type if input_type response = connection.post((model:), payload) (response, model: model_id(model), text:) end |
#embedding_url ⇒ Object
141 |
# File 'lib/legion/extensions/llm/azure_foundry/provider.rb', line 141 def (**) = path_for('embeddings') |
#headers ⇒ Object
130 131 132 133 134 135 |
# File 'lib/legion/extensions/llm/azure_foundry/provider.rb', line 130 def headers { 'api-key' => config.azure_foundry_api_key, 'Authorization' => bearer_header }.compact end |
#health(live: false) ⇒ Object
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
# File 'lib/legion/extensions/llm/azure_foundry/provider.rb', line 172 def health(live: false) baseline = { provider: :azure_foundry, configured: configured?, ready: configured?, live: live, api_base: api_base, surface: surface } return baseline.merge(checked: false) unless live response = connection.get(health_url) baseline.merge(checked: true, model_info: response.body) rescue StandardError => e baseline.merge(checked: true, ready: false, error: e.class.name, message: e.) end |
#health_url ⇒ Object
142 |
# File 'lib/legion/extensions/llm/azure_foundry/provider.rb', line 142 def health_url = models_url |
#list_models ⇒ Object
195 196 197 198 199 |
# File 'lib/legion/extensions/llm/azure_foundry/provider.rb', line 195 def list_models models = discover_offerings(live: false).map { |offering| model_info_from_offering(offering) } self.class.registry_publisher.publish_models_async(models, readiness: readiness(live: false)) models end |
#models_url ⇒ Object
140 |
# File 'lib/legion/extensions/llm/azure_foundry/provider.rb', line 140 def models_url = path_for('info') |
#offering_for(model:, model_family: nil, canonical_model_alias: nil, instance_id: :default, usage_type: nil, **metadata) ⇒ Object
rubocop:disable Metrics/ParameterLists
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/legion/extensions/llm/azure_foundry/provider.rb', line 155 def offering_for(model:, model_family: nil, canonical_model_alias: nil, instance_id: :default, # rubocop:disable Metrics/ParameterLists usage_type: nil, **) deployment = self.class.deployment_config(model, config:) model_id = self.class.resolve_model_id(model, config:) configured_family = value_for(deployment, :model_family) configured_alias = value_for(deployment, :canonical_model_alias) build_offering( model: model_id, instance_id: instance_id, model_family: normalize_family(model_family || configured_family || infer_model_family(model_id)), canonical_model_alias: canonical_model_alias || configured_alias, usage_type: usage_type || value_for(deployment, :usage_type) || usage_type_for(model_id), metadata: .merge((deployment)) ) end |
#readiness(live: false) ⇒ Object
189 190 191 192 193 |
# File 'lib/legion/extensions/llm/azure_foundry/provider.rb', line 189 def readiness(live: false) health(live: live).merge(local: false, remote: true, endpoints: endpoint_manifest).tap do || self.class.registry_publisher.publish_readiness_async() if live end end |
#stream(messages, model:, temperature: nil, max_tokens: nil, tools: {}, tool_prefs: nil, params: {}) ⇒ Object
rubocop:disable Metrics/ParameterLists
205 206 207 |
# File 'lib/legion/extensions/llm/azure_foundry/provider.rb', line 205 def stream(, model:, temperature: nil, max_tokens: nil, tools: {}, tool_prefs: nil, params: {}, &) # rubocop:disable Metrics/ParameterLists complete(, tools:, temperature:, model: model_info(model, max_tokens:), params:, tool_prefs:, &) end |
#stream_url ⇒ Object
139 |
# File 'lib/legion/extensions/llm/azure_foundry/provider.rb', line 139 def stream_url = completion_url |