Class: LLM::Provider Abstract
- Inherits:
-
Object
- Object
- LLM::Provider
- Includes:
- Transport::Execution
- Defined in:
- lib/llm/provider.rb
Overview
Instance Method Summary collapse
-
#retry_errors ⇒ Array<Exception>
Returns an array of exceptions that a request could raise and that will be retried up to #retry_budget times.
-
#build_messages(prompt, params, role, key: :messages) ⇒ Array<LLM::Message>
Builds the outgoing message array for a turn.
-
#inspect ⇒ String
Returns an inspection of the provider object.
-
#name ⇒ Symbol
Returns the provider's name.
- #host ⇒ String
- #port ⇒ Integer
-
#registry ⇒ LLM::Registry
Returns the provider's model registry.
-
#embed(input, model: nil, **params) ⇒ LLM::Response
Provides an embedding.
- #ocr ⇒ LLM::Response
-
#complete(prompt, params = {}) ⇒ LLM::Response
Provides an interface to the chat completions API.
-
#chat(prompt, params = {}) ⇒ LLM::Context
Starts a new chat powered by the chat completions API.
-
#respond(prompt, params = {}) ⇒ LLM::Context
Starts a new chat powered by the responses API.
-
#responses ⇒ LLM::OpenAI::Responses
Compared to the chat completions API, the responses API can require less bandwidth on each turn, maintain state server-side, and produce faster responses.
-
#images ⇒ LLM::OpenAI::Images, LLM::Google::Images
Returns an interface to the images API.
-
#audio ⇒ LLM::OpenAI::Audio
Returns an interface to the audio API.
-
#files ⇒ LLM::OpenAI::Files
Returns an interface to the files API.
-
#models ⇒ LLM::OpenAI::Models
Returns an interface to the models API.
-
#moderations ⇒ LLM::OpenAI::Moderations
Returns an interface to the moderations API.
-
#vector_stores ⇒ LLM::OpenAI::VectorStore
Returns an interface to the vector stores API.
-
#default_model ⇒ String
Returns the default model for chat completions.
-
#retry_budget ⇒ Integer
Returns the number of times a rate-limited request is retried before the error is raised.
-
#schema ⇒ LLM::Schema
Returns an object that can generate a JSON schema.
-
#with(**headers) { ... } ⇒ LLM::Provider
Add one or more headers to all requests, or scope them to a block.
-
#server_tools ⇒ String => LLM::ServerTool
Returns all known tools provided by a provider.
-
#server_tool(name, options = {}) ⇒ LLM::ServerTool
Returns a tool provided by a provider.
-
#web_search(query:) ⇒ LLM::Response
Provides a web search capability.
-
#assistant_role ⇒ Symbol
Returns the role of the assistant in the conversation.
- #user_role ⇒ Symbol
- #system_role ⇒ Symbol
- #developer_role ⇒ Symbol
- #tool_role ⇒ Symbol
-
#tracer ⇒ LLM::Tracer
Returns the current scoped tracer override or provider default tracer.
-
#tracer=(tracer)
Set the provider's default tracer This tracer is shared by the provider instance and becomes the fallback whenever no scoped override is active.
-
#with_tracer(tracer) { ... } ⇒ Object
Override the tracer for the current fiber while the block runs.
-
#interrupt!(owner) ⇒ nil
(also: #cancel!)
Interrupt the active request, if any.
-
#request_owner ⇒ Object
private
Returns the current request owner used by the transport.
-
#key? ⇒ Boolean
Returns true when an API key is configured.
-
#adapt_function(fn) ⇒ Hash
abstract
Adapt a Function to the provider-specific tool schema.
-
#initialize(key:, host:, port: 443, timeout: 240, read_timeout: nil, connect_timeout: 5, ssl: true, base_path: "", persistent: false, transport: nil) ⇒ Provider
constructor
A new instance of Provider.
Constructor Details
#initialize(key:, host:, port: 443, timeout: 240, read_timeout: nil, connect_timeout: 5, ssl: true, base_path: "", persistent: false, transport: nil) ⇒ Provider
Returns a new instance of Provider.
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/llm/provider.rb', line 35 def initialize(key:, host:, port: 443, timeout: 240, read_timeout: nil, connect_timeout: 5, ssl: true, base_path: "", persistent: false, transport: nil) @key = key @host = host @port = port @read_timeout = read_timeout || timeout @timeout = @read_timeout @connect_timeout = connect_timeout @ssl = ssl @base_path = LLM::Utils.normalize_base_path(base_path) @base_uri = URI("#{ssl ? "https" : "http"}://#{host}:#{port}/") @headers = {"User-Agent" => "llm.rb v#{LLM::VERSION}"} @monitor = Monitor.new @transport = LLM::Transport::Utils.resolve_transport( host:, port:, timeout: @read_timeout, connect_timeout: @connect_timeout, ssl:, transport:, persistent: ) end |
Instance Method Details
#retry_errors ⇒ Array<Exception>
Returns an array of exceptions that a request could raise and that will be retried up to #retry_budget times.
501 502 503 504 505 506 507 508 509 510 |
# File 'lib/llm/provider.rb', line 501 def retry_errors [ LLM::InsufficientQuotaError, LLM::RateLimitError, SystemCallError, Net::ReadTimeout, Net::WriteTimeout, Net::OpenTimeout ] end |
#build_messages(prompt, params, role, key: :messages) ⇒ Array<LLM::Message>
Builds the outgoing message array for a turn. Normalizes the prompt into one or more Message objects and prepends the existing history.
The method is idempotent. If the prompt is already an Message or an array of Messages (ie it was built by a previous call and possibly transformed), it is returned as-is without rebuilding.
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/llm/provider.rb', line 77 def (prompt, params, role, key: :messages) case prompt when LLM::Message [prompt] when Array if prompt.all? { LLM::Message === _1 } prompt else [*(params.delete(key) || []), LLM::Message.new(role, prompt)] end when LLM::Prompt [*(params.delete(key) || []), *prompt.to_a] else [*(params.delete(key) || []), LLM::Message.new(role, prompt)] end end |
#inspect ⇒ String
The secret key is redacted in inspect for security reasons
Returns an inspection of the provider object
98 99 100 |
# File 'lib/llm/provider.rb', line 98 def inspect "#<#{LLM::Utils.object_id(self)} @key=[REDACTED] @transport=#{transport.inspect} @tracer=#{tracer.inspect}>" end |
#name ⇒ Symbol
Returns the provider's name
107 108 109 |
# File 'lib/llm/provider.rb', line 107 def name raise NotImplementedError end |
#host ⇒ String
113 114 115 |
# File 'lib/llm/provider.rb', line 113 def host @host end |
#port ⇒ Integer
119 120 121 |
# File 'lib/llm/provider.rb', line 119 def port @port end |
#registry ⇒ LLM::Registry
Returns the provider's model registry.
126 127 128 |
# File 'lib/llm/provider.rb', line 126 def registry LLM.registry_for(self) end |
#embed(input, model: nil, **params) ⇒ LLM::Response
Provides an embedding
141 142 143 |
# File 'lib/llm/provider.rb', line 141 def (input, model: nil, **params) raise NotImplementedError end |
#ocr ⇒ LLM::Response
This feature is not implemented by all providers, and it will raise NotImplementedError for providers that do not support it.
151 152 153 |
# File 'lib/llm/provider.rb', line 151 def ocr(...) raise NotImplementedError end |
#complete(prompt, params = {}) ⇒ LLM::Response
Provides an interface to the chat completions API. Most users should use Context#talk or Agent#talk instead.
177 178 179 |
# File 'lib/llm/provider.rb', line 177 def complete(prompt, params = {}) raise NotImplementedError end |
#chat(prompt, params = {}) ⇒ LLM::Context
Starts a new chat powered by the chat completions API
186 187 188 189 |
# File 'lib/llm/provider.rb', line 186 def chat(prompt, params = {}) role = params.delete(:role) LLM::Context.new(self, params).talk(prompt, role:) end |
#respond(prompt, params = {}) ⇒ LLM::Context
Starts a new chat powered by the responses API
197 198 199 200 |
# File 'lib/llm/provider.rb', line 197 def respond(prompt, params = {}) role = params.delete(:role) LLM::Context.new(self, params).respond(prompt, role:) end |
#responses ⇒ LLM::OpenAI::Responses
Compared to the chat completions API, the responses API can require less bandwidth on each turn, maintain state server-side, and produce faster responses.
209 210 211 |
# File 'lib/llm/provider.rb', line 209 def responses raise NotImplementedError end |
#images ⇒ LLM::OpenAI::Images, LLM::Google::Images
Returns an interface to the images API
216 217 218 |
# File 'lib/llm/provider.rb', line 216 def images raise NotImplementedError end |
#audio ⇒ LLM::OpenAI::Audio
Returns an interface to the audio API
223 224 225 |
# File 'lib/llm/provider.rb', line 223 def audio raise NotImplementedError end |
#files ⇒ LLM::OpenAI::Files
Returns an interface to the files API
230 231 232 |
# File 'lib/llm/provider.rb', line 230 def files raise NotImplementedError end |
#models ⇒ LLM::OpenAI::Models
Returns an interface to the models API
237 238 239 |
# File 'lib/llm/provider.rb', line 237 def models raise NotImplementedError end |
#moderations ⇒ LLM::OpenAI::Moderations
Returns an interface to the moderations API
244 245 246 |
# File 'lib/llm/provider.rb', line 244 def moderations raise NotImplementedError end |
#vector_stores ⇒ LLM::OpenAI::VectorStore
Returns an interface to the vector stores API
251 252 253 |
# File 'lib/llm/provider.rb', line 251 def vector_stores raise NotImplementedError end |
#default_model ⇒ String
Returns the default model for chat completions
258 259 260 |
# File 'lib/llm/provider.rb', line 258 def default_model raise NotImplementedError end |
#retry_budget ⇒ Integer
Returns the number of times a rate-limited request is retried before the error is raised.
Each retry sleeps a growing interval, so a budget that is exhausted surfaces the rate-limit error instead of blocking indefinitely. A provider can return a different budget when its API recovers from rate limits more slowly.
274 275 276 |
# File 'lib/llm/provider.rb', line 274 def retry_budget 5 end |
#schema ⇒ LLM::Schema
Returns an object that can generate a JSON schema
281 282 283 |
# File 'lib/llm/provider.rb', line 281 def schema LLM::Schema.new end |
#with(**headers) { ... } ⇒ LLM::Provider
For backwards compatibility, headers can be
provided via the headers: keyword argument,
or provided directly as a Hash without the
headers: key namespace.
Add one or more headers to all requests, or scope them to a block.
Without a block the headers are merged into the provider's defaults
permanently. With a block the headers apply only to the current fiber,
for the duration of the block, then the previous headers are restored.
This is useful for a header that varies per context, such as
OpenRouter's x-session-id.
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 |
# File 'lib/llm/provider.rb', line 311 def with(**headers, &block) headers = headers.merge(headers.delete(:headers) || {}) if block wm = weakmaps.header previous = wm[self] wm[self] = (previous || {}).merge(headers) block.call else lock { tap { @headers.merge!(headers) } } end ensure if block if previous.nil? wm.respond_to?(:delete) ? wm.delete(self) : wm[self] = nil else wm[self] = previous end end end |
#server_tools ⇒ String => LLM::ServerTool
This method might be outdated, and the LLM::Provider#server_tool method can be used if a tool is not found here.
Returns all known tools provided by a provider.
337 338 339 |
# File 'lib/llm/provider.rb', line 337 def server_tools {} end |
#server_tool(name, options = {}) ⇒ LLM::ServerTool
OpenAI, Anthropic, and Gemini provide platform-tools for things like web search, and more.
Returns a tool provided by a provider.
354 355 356 |
# File 'lib/llm/provider.rb', line 354 def server_tool(name, = {}) LLM::ServerTool.new(name, , self) end |
#web_search(query:) ⇒ LLM::Response
Provides a web search capability
364 365 366 |
# File 'lib/llm/provider.rb', line 364 def web_search(query:) raise NotImplementedError end |
#assistant_role ⇒ Symbol
Returns the role of the assistant in the conversation.
371 372 373 |
# File 'lib/llm/provider.rb', line 371 def assistant_role :assistant end |
#user_role ⇒ Symbol
377 378 379 |
# File 'lib/llm/provider.rb', line 377 def user_role :user end |
#system_role ⇒ Symbol
383 384 385 |
# File 'lib/llm/provider.rb', line 383 def system_role :system end |
#developer_role ⇒ Symbol
389 390 391 |
# File 'lib/llm/provider.rb', line 389 def developer_role :developer end |
#tool_role ⇒ Symbol
395 396 397 |
# File 'lib/llm/provider.rb', line 395 def tool_role :tool end |
#tracer ⇒ LLM::Tracer
Returns the current scoped tracer override or provider default tracer
402 403 404 |
# File 'lib/llm/provider.rb', line 402 def tracer weakmaps.tracer[self] || @tracer || LLM::Tracer::Null.new(self) end |
#tracer=(tracer)
This method returns an undefined value.
Set the provider's default tracer This tracer is shared by the provider instance and becomes the fallback whenever no scoped override is active.
A tracer assigned this way is not scoped, so nothing declares when it is finished and Tracer#on_exit never fires for it. Release what it holds when the provider is done with, or scope it with #with_tracer instead.
425 426 427 |
# File 'lib/llm/provider.rb', line 425 def tracer=(tracer) @tracer = tracer || LLM::Tracer::Null.new(self) end |
#with_tracer(tracer) { ... } ⇒ Object
Override the tracer for the current fiber while the block runs. This is useful when you want per-request or per-turn tracing without replacing the provider's default tracer.
440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 |
# File 'lib/llm/provider.rb', line 440 def with_tracer(tracer) scoped = tracer || LLM::Tracer::Null.new(self) wm = weakmaps.tracer had_override = wm.key?(self) previous = wm[self] wm[self] = scoped entered = LLM::Tracer.enter(scoped) yield ensure if had_override wm[self] = previous else wm.respond_to?(:delete) ? wm.delete(self) : wm[self] = nil end ## # The scope this tracer was opened for is over, and the tracer is # told so when the last one that is open for it ends - on whichever # thread that happens, because a tool opens a scope of its own for # the turn's tracer. LLM::Tracer.exit(scoped) if entered end |
#interrupt!(owner) ⇒ nil Also known as: cancel!
Interrupt the active request, if any.
466 467 468 |
# File 'lib/llm/provider.rb', line 466 def interrupt!(owner) transport.interrupt!(owner) end |
#request_owner ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns the current request owner used by the transport.
475 476 477 |
# File 'lib/llm/provider.rb', line 475 def request_owner transport.request_owner end |
#key? ⇒ Boolean
Returns true when an API key is configured
482 483 484 |
# File 'lib/llm/provider.rb', line 482 def key? @key != nil && @key.to_s.strip.size > 0 end |
#adapt_function(fn) ⇒ Hash
Adapt a Function to the provider-specific tool schema.
492 493 494 |
# File 'lib/llm/provider.rb', line 492 def adapt_function(fn) raise NotImplementedError end |