Class: Ask::Provider
- Inherits:
-
Object
- Object
- Ask::Provider
- Defined in:
- lib/ask/provider.rb
Overview
Abstract base class for all LLM providers. Defines the interface that provider gems (ask-openai, ask-anthropic, etc.) must implement.
Provider gems subclass this and implement the abstract methods:
-
#chat — send a chat completion request
-
#embed — generate embeddings
-
#list_models — list available models
-
#api_base — provider API base URL
Providers register themselves via Provider.register so that Provider.resolve returns the correct class by name.
Instance Attribute Summary collapse
-
#config ⇒ Object
readonly
The configuration object passed to the constructor.
Class Method Summary collapse
-
.assume_models_exist? ⇒ Boolean
Whether all models can be assumed to exist.
-
.capabilities ⇒ Hash?
Capabilities.
-
.clear_providers! ⇒ Object
Clear all registered providers (used in testing).
-
.configuration_options ⇒ Array<Symbol>
Config keys this provider supports.
-
.configuration_requirements ⇒ Array<Symbol>
Config keys this provider requires.
-
.configured?(config) ⇒ Boolean
Check if this provider is fully configured.
-
.local? ⇒ Boolean
True if this provider runs locally.
-
.name ⇒ String
Class name without module prefix.
-
.providers ⇒ Hash{Symbol => Class<Ask::Provider>}
Return a shallow copy of all registered providers.
-
.register(name, provider_class) ⇒ Object
Register a provider class so it can be resolved by name.
-
.remote? ⇒ Boolean
True if this provider requires a remote API.
-
.resolve(name) ⇒ Class<Ask::Provider>
Resolve a registered provider by name.
-
.slug ⇒ String
Lowercased, underscored slug from the class name.
Instance Method Summary collapse
- #api_base ⇒ String abstract
-
#assume_models_exist? ⇒ Boolean
True if all models can be assumed to exist.
-
#capabilities ⇒ Hash?
Provider capabilities metadata.
-
#chat(messages, model:, tools: nil, temperature: nil, stream: nil, schema: nil, **params) {|Ask::Chunk| ... } ⇒ Ask::Message
Send a chat completion request.
-
#embed(text, model:) ⇒ Array<Float>
Generate embeddings for the given text.
-
#headers ⇒ Hash<String, String>
Additional HTTP headers for API requests.
-
#initialize(config = {}) ⇒ Provider
constructor
A new instance of Provider.
-
#list_models ⇒ Array<Ask::ModelInfo>
List available models from this provider.
-
#local? ⇒ Boolean
True if the provider runs locally (e.g., Ollama).
-
#name ⇒ String
Provider name (demodulized class name).
-
#parse_error(response) ⇒ String?
Parse an error response body into a human-readable message.
-
#remote? ⇒ Boolean
True if the provider requires a remote API.
-
#slug ⇒ String
Lowercased provider slug.
Constructor Details
#initialize(config = {}) ⇒ Provider
Returns a new instance of Provider.
35 36 37 38 |
# File 'lib/ask/provider.rb', line 35 def initialize(config = {}) @config = config ensure_configured! end |
Instance Attribute Details
#config ⇒ Object (readonly)
Returns the configuration object passed to the constructor.
32 33 34 |
# File 'lib/ask/provider.rb', line 32 def config @config end |
Class Method Details
.assume_models_exist? ⇒ Boolean
Returns whether all models can be assumed to exist.
203 204 205 |
# File 'lib/ask/provider.rb', line 203 def assume_models_exist? false end |
.capabilities ⇒ Hash?
Returns capabilities.
171 172 173 |
# File 'lib/ask/provider.rb', line 171 def capabilities nil end |
.clear_providers! ⇒ Object
Clear all registered providers (used in testing).
152 153 154 155 156 |
# File 'lib/ask/provider.rb', line 152 def clear_providers! REGISTRY_MUTEX.synchronize do @registry = {} end end |
.configuration_options ⇒ Array<Symbol>
Returns config keys this provider supports.
176 177 178 |
# File 'lib/ask/provider.rb', line 176 def [] end |
.configuration_requirements ⇒ Array<Symbol>
Returns config keys this provider requires.
181 182 183 |
# File 'lib/ask/provider.rb', line 181 def configuration_requirements [] end |
.configured?(config) ⇒ Boolean
Check if this provider is fully configured.
188 189 190 |
# File 'lib/ask/provider.rb', line 188 def configured?(config) configuration_requirements.all? { |req| config.respond_to?(req) && config.public_send(req) } end |
.local? ⇒ Boolean
Returns true if this provider runs locally.
193 194 195 |
# File 'lib/ask/provider.rb', line 193 def local? false end |
.name ⇒ String
Returns class name without module prefix.
166 167 168 |
# File 'lib/ask/provider.rb', line 166 def name to_s.split("::").last end |
.providers ⇒ Hash{Symbol => Class<Ask::Provider>}
Return a shallow copy of all registered providers. Thread-safe via REGISTRY_MUTEX.
145 146 147 148 149 |
# File 'lib/ask/provider.rb', line 145 def providers REGISTRY_MUTEX.synchronize do registry.dup end end |
.register(name, provider_class) ⇒ Object
Register a provider class so it can be resolved by name. Thread-safe via REGISTRY_MUTEX.
123 124 125 126 127 |
# File 'lib/ask/provider.rb', line 123 def register(name, provider_class) REGISTRY_MUTEX.synchronize do registry[name.to_sym] = provider_class end end |
.remote? ⇒ Boolean
Returns true if this provider requires a remote API.
198 199 200 |
# File 'lib/ask/provider.rb', line 198 def remote? !local? end |
.resolve(name) ⇒ Class<Ask::Provider>
Resolve a registered provider by name. Thread-safe via REGISTRY_MUTEX.
134 135 136 137 138 139 140 |
# File 'lib/ask/provider.rb', line 134 def resolve(name) REGISTRY_MUTEX.synchronize do registry[name.to_sym] || raise(UnknownProvider, "Unknown provider: #{name.inspect}. " \ "Available: #{registry.keys.join(', ')}") end end |
.slug ⇒ String
Returns lowercased, underscored slug from the class name.
159 160 161 162 163 |
# File 'lib/ask/provider.rb', line 159 def slug name.split("::").last.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2') .gsub(/([a-z\d])([A-Z])/, '\1_\2') .downcase end |
Instance Method Details
#api_base ⇒ String
The base URL for this provider’s API.
71 72 73 |
# File 'lib/ask/provider.rb', line 71 def api_base raise NotImplementedError, "#{self.class} must implement #api_base" end |
#assume_models_exist? ⇒ Boolean
Returns true if all models can be assumed to exist.
97 |
# File 'lib/ask/provider.rb', line 97 def assume_models_exist? = self.class.assume_models_exist? |
#capabilities ⇒ Hash?
Returns provider capabilities metadata.
112 113 114 |
# File 'lib/ask/provider.rb', line 112 def capabilities self.class.capabilities end |
#chat(messages, model:, tools: nil, temperature: nil, stream: nil, schema: nil, **params) {|Ask::Chunk| ... } ⇒ Ask::Message
Send a chat completion request.
51 52 53 |
# File 'lib/ask/provider.rb', line 51 def chat(, model:, tools: nil, temperature: nil, stream: nil, schema: nil, **params, &block) raise NotImplementedError, "#{self.class} must implement #chat" end |
#embed(text, model:) ⇒ Array<Float>
Generate embeddings for the given text.
59 60 61 |
# File 'lib/ask/provider.rb', line 59 def (text, model:) raise NotImplementedError, "#{self.class} must implement #embed" end |
#headers ⇒ Hash<String, String>
Additional HTTP headers for API requests.
79 80 81 |
# File 'lib/ask/provider.rb', line 79 def headers {} end |
#list_models ⇒ Array<Ask::ModelInfo>
List available models from this provider.
65 66 67 |
# File 'lib/ask/provider.rb', line 65 def list_models raise NotImplementedError, "#{self.class} must implement #list_models" end |
#local? ⇒ Boolean
Returns true if the provider runs locally (e.g., Ollama).
91 |
# File 'lib/ask/provider.rb', line 91 def local? = self.class.local? |
#name ⇒ String
Returns provider name (demodulized class name).
107 108 109 |
# File 'lib/ask/provider.rb', line 107 def name self.class.name end |
#parse_error(response) ⇒ String?
Parse an error response body into a human-readable message.
86 87 88 |
# File 'lib/ask/provider.rb', line 86 def parse_error(response) nil end |
#remote? ⇒ Boolean
Returns true if the provider requires a remote API.
94 |
# File 'lib/ask/provider.rb', line 94 def remote? = !local? |
#slug ⇒ String
Returns lowercased provider slug.
102 103 104 |
# File 'lib/ask/provider.rb', line 102 def slug self.class.slug end |