Module: Llm::Client

Defined in:
lib/llm/client.rb

Overview

Facade for LLM completion with retry logic and graceful fallback. Returns nil on any failure — callers should always have a non-AI fallback.

Constant Summary collapse

MAX_RETRIES =
3
BASE_DELAY =
1
RETRYABLE_ERRORS =

Only retry on transient network errors, not configuration or API errors

[
  Net::OpenTimeout, Net::ReadTimeout, Errno::ECONNREFUSED,
  Errno::ECONNRESET, Errno::ETIMEDOUT, SocketError
].freeze

Class Method Summary collapse

Class Method Details

.available?Boolean

Returns:

  • (Boolean)


41
42
43
44
45
46
47
# File 'lib/llm/client.rb', line 41

def available?
  config = Config.new
  return false unless config.configured?

  provider = config.build_provider
  provider&.available? || false
end

.complete(prompt, system_prompt: nil) ⇒ Object



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/llm/client.rb', line 20

def complete(prompt, system_prompt: nil)
  provider = build_provider
  return nil unless provider

  attempt = 0
  begin
    attempt += 1
    provider.complete(prompt, system_prompt:)
  rescue *RETRYABLE_ERRORS => e
    if attempt < MAX_RETRIES
      sleep(BASE_DELAY * (2**(attempt - 1)))
      retry
    end
    warn "[Ruby Raider] LLM failed after #{MAX_RETRIES} attempts: #{e.message}"
    nil
  rescue StandardError => e
    warn "[Ruby Raider] LLM error: #{e.message}"
    nil
  end
end

.statusObject



49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/llm/client.rb', line 49

def status
  config = Config.new
  return { configured: false, provider: nil } unless config.configured?

  provider = config.build_provider
  {
    configured: true,
    provider: config.provider_name,
    model: config.model,
    available: provider&.available? || false
  }
end