Class: RubyPi::LLM::Fallback
- Inherits:
-
BaseProvider
- Object
- BaseProvider
- RubyPi::LLM::Fallback
- Defined in:
- lib/ruby_pi/llm/fallback.rb
Overview
A resilient provider wrapper that tries a primary provider first and automatically falls back to an alternative provider on failure. Both providers must conform to the BaseProvider interface.
Authentication errors are NOT retried with the fallback since they indicate a configuration problem rather than a transient failure.
Issue #23 + Issue #12: When streaming, events flow from the primary provider directly to the consumer in real time (no buffering), preserving the streaming UX on the happy path. If the primary fails mid-stream, a :fallback_start StreamEvent is emitted before the fallback takes over, so the consumer can discard any partial output already rendered from the failed primary. (The agent loop translates :fallback_start into a :provider_fallback event; raw Fallback consumers should handle :fallback_start themselves.)
Instance Attribute Summary collapse
-
#fallback ⇒ RubyPi::LLM::BaseProvider
readonly
The fallback provider.
-
#primary ⇒ RubyPi::LLM::BaseProvider
readonly
The primary provider.
Attributes inherited from BaseProvider
#max_retries, #retry_base_delay, #retry_max_delay
Instance Method Summary collapse
-
#complete(messages:, tools: [], stream: false) {|event| ... } ⇒ RubyPi::LLM::Response
Overrides BaseProvider#complete to skip the outer retry wrapper.
-
#initialize(primary:, fallback:, **options) ⇒ Fallback
constructor
Creates a new Fallback wrapper with a primary and fallback provider.
-
#model_name ⇒ String
Returns the model name of the primary provider.
-
#provider_name ⇒ Symbol
Returns :fallback as the provider identifier.
Constructor Details
#initialize(primary:, fallback:, **options) ⇒ Fallback
Creates a new Fallback wrapper with a primary and fallback provider.
47 48 49 50 51 |
# File 'lib/ruby_pi/llm/fallback.rb', line 47 def initialize(primary:, fallback:, **) super(**) @primary = primary @fallback = fallback end |
Instance Attribute Details
#fallback ⇒ RubyPi::LLM::BaseProvider (readonly)
Returns the fallback provider.
40 41 42 |
# File 'lib/ruby_pi/llm/fallback.rb', line 40 def fallback @fallback end |
#primary ⇒ RubyPi::LLM::BaseProvider (readonly)
Returns the primary provider.
37 38 39 |
# File 'lib/ruby_pi/llm/fallback.rb', line 37 def primary @primary end |
Instance Method Details
#complete(messages:, tools: [], stream: false) {|event| ... } ⇒ RubyPi::LLM::Response
Overrides BaseProvider#complete to skip the outer retry wrapper.
Without this override, Fallback inherits BaseProvider#complete which wraps perform_complete in a retry loop. Since perform_complete calls (also with retries), the retry layers compose multiplicatively:
outer_retries x (primary_retries + fallback_retries)
With default max_retries=3, that’s 4 x (4 + 4) = 32 total attempts instead of the expected 4 + 4 = 8.
This override calls perform_complete directly — no outer retry loop. Each inner provider handles its own retries independently.
85 86 87 |
# File 'lib/ruby_pi/llm/fallback.rb', line 85 def complete(messages:, tools: [], stream: false, &block) perform_complete(messages: , tools: tools, stream: stream, &block) end |
#model_name ⇒ String
Returns the model name of the primary provider.
56 57 58 |
# File 'lib/ruby_pi/llm/fallback.rb', line 56 def model_name @primary.model_name end |
#provider_name ⇒ Symbol
Returns :fallback as the provider identifier.
63 64 65 |
# File 'lib/ruby_pi/llm/fallback.rb', line 63 def provider_name :fallback end |