Class: RubyPi::LLM::BaseProvider

Inherits:
Object
  • Object
show all
Defined in:
lib/ruby_pi/llm/base_provider.rb

Overview

Abstract base class that defines the contract every LLM provider must fulfill. Provides built-in retry logic with exponential backoff for transient errors and a unified #complete interface for both synchronous and streaming completions.

Subclasses MUST implement:

  • #perform_complete(messages:, tools:, stream:, &block)

  • #model_name

  • #provider_name

Examples:

Subclass implementation

class MyProvider < RubyPi::LLM::BaseProvider
  def model_name = "my-model"
  def provider_name = :my_provider

  private
  def perform_complete(messages:, tools:, stream:, &block)
    # Make HTTP request and return RubyPi::LLM::Response
  end
end

Direct Known Subclasses

Anthropic, Fallback, Gemini, OpenAI

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(max_retries: nil, retry_base_delay: nil, retry_max_delay: nil) ⇒ BaseProvider

Initializes the base provider with retry configuration.

Parameters:

  • max_retries (Integer, nil) (defaults to: nil)

    override max retries (defaults to global config)

  • retry_base_delay (Float, nil) (defaults to: nil)

    override base delay (defaults to global config)

  • retry_max_delay (Float, nil) (defaults to: nil)

    override max delay (defaults to global config)



47
48
49
50
51
52
# File 'lib/ruby_pi/llm/base_provider.rb', line 47

def initialize(max_retries: nil, retry_base_delay: nil, retry_max_delay: nil)
  config = RubyPi.configuration
  @max_retries = max_retries || config.max_retries
  @retry_base_delay = retry_base_delay || config.retry_base_delay
  @retry_max_delay = retry_max_delay || config.retry_max_delay
end

Instance Attribute Details

#max_retriesInteger (readonly)

Returns maximum number of retry attempts.

Returns:

  • (Integer)

    maximum number of retry attempts



34
35
36
# File 'lib/ruby_pi/llm/base_provider.rb', line 34

def max_retries
  @max_retries
end

#retry_base_delayFloat (readonly)

Returns base delay in seconds for exponential backoff.

Returns:

  • (Float)

    base delay in seconds for exponential backoff



37
38
39
# File 'lib/ruby_pi/llm/base_provider.rb', line 37

def retry_base_delay
  @retry_base_delay
end

#retry_max_delayFloat (readonly)

Returns maximum delay in seconds between retries.

Returns:

  • (Float)

    maximum delay in seconds between retries



40
41
42
# File 'lib/ruby_pi/llm/base_provider.rb', line 40

def retry_max_delay
  @retry_max_delay
end

Instance Method Details

#complete(messages:, tools: [], stream: false) {|event| ... } ⇒ RubyPi::LLM::Response

Sends a completion request to the LLM provider with automatic retry logic for transient errors. When stream is true and a block is given, yields StreamEvent objects incrementally as they arrive.

Parameters:

  • messages (Array<Hash>)

    conversation messages, each with :role and :content

  • tools (Array<Hash>) (defaults to: [])

    tool/function definitions for the model

  • stream (Boolean) (defaults to: false)

    whether to enable streaming mode

Yields:

  • (event)

    yields StreamEvent objects when streaming

Yield Parameters:

Returns:

Raises:



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/ruby_pi/llm/base_provider.rb', line 68

def complete(messages:, tools: [], stream: false, &block)
  attempt = 0

  begin
    attempt += 1
    perform_complete(messages: messages, tools: tools, stream: stream, &block)
  rescue RubyPi::AuthenticationError
    # Authentication errors are not retryable — raise immediately
    raise
  rescue RubyPi::RateLimitError, RubyPi::ApiError, RubyPi::TimeoutError => e
    if attempt < @max_retries
      delay = calculate_backoff(attempt)
      log_retry(attempt, delay, e)
      sleep(delay)
      retry
    else
      raise
    end
  end
end

#model_nameString

Returns the model name used by this provider instance. Subclasses MUST override this method.

Returns:

  • (String)

    the model identifier

Raises:



94
95
96
# File 'lib/ruby_pi/llm/base_provider.rb', line 94

def model_name
  raise RubyPi::NotImplementedError, :model_name
end

#provider_nameSymbol

Returns the provider identifier. Subclasses MUST override this method.

Returns:

  • (Symbol)

    the provider identifier (e.g., :gemini, :anthropic, :openai)

Raises:



103
104
105
# File 'lib/ruby_pi/llm/base_provider.rb', line 103

def provider_name
  raise RubyPi::NotImplementedError, :provider_name
end