Class: SavvyOpenrouter::CompletionRetryPolicy

Inherits:
Object
  • Object
show all
Defined in:
lib/savvy_openrouter/completion_retry_policy.rb

Overview

Controls optional retries for Chat#completions (non-streaming): empty/zero-token completions and selected HTTP errors from OpenRouter.

Constant Summary collapse

DEFAULT_ON =
{
  "zero_completion_tokens" => true,
  "empty_assistant_content" => true,
  "rate_limit" => true,
  "bad_gateway" => true,
  "internal_server_error" => true,
  "service_unavailable" => true
}.freeze

Instance Method Summary collapse

Constructor Details

#initialize(raw) ⇒ CompletionRetryPolicy

Returns a new instance of CompletionRetryPolicy.



16
17
18
19
20
21
22
23
24
# File 'lib/savvy_openrouter/completion_retry_policy.rb', line 16

def initialize(raw)
  @raw =
    case raw
    when false, nil then {}
    when Hash then Configuration.stringify_keys_static(raw)
    else
      raise ArgumentError, "chat_retries must be a Hash or false"
    end
end

Instance Method Details

#enabled?Boolean

Returns:

  • (Boolean)


32
33
34
# File 'lib/savvy_openrouter/completion_retry_policy.rb', line 32

def enabled?
  max_attempts > 1
end

#max_attemptsObject



26
27
28
29
30
# File 'lib/savvy_openrouter/completion_retry_policy.rb', line 26

def max_attempts
  n = @raw["max_attempts"]
  i = Integer(n, exception: false)
  i&.positive? ? i : 1
end

#retry_http_error?(error) ⇒ Boolean

Returns:

  • (Boolean)


36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/savvy_openrouter/completion_retry_policy.rb', line 36

def retry_http_error?(error)
  return false unless enabled?
  return false unless error.is_a?(SavvyOpenrouter::ApiError)

  code = error.status_code
  return false unless code

  flag =
    case code
    when 429 then "rate_limit"
    when 502 then "bad_gateway"
    when 500, 501 then "internal_server_error"
    when 503 then "service_unavailable"
    end
  flag ? on?(flag) : false
end

#retry_response?(response) ⇒ Boolean

Returns:

  • (Boolean)


53
54
55
56
57
58
# File 'lib/savvy_openrouter/completion_retry_policy.rb', line 53

def retry_response?(response)
  return false unless enabled?

  (on?("zero_completion_tokens") && zero_completion_tokens?(response)) ||
    (on?("empty_assistant_content") && empty_assistant_content?(response))
end

#wait_after_attempt(attempt_number) ⇒ Object



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/savvy_openrouter/completion_retry_policy.rb', line 60

def wait_after_attempt(attempt_number)
  base = integer_opt(@raw["base_delay_ms"], 400)
  max_d = integer_opt(@raw["max_delay_ms"], 10_000)
  exponential = @raw["exponential_backoff"] != false
  jitter_ratio = float_opt(@raw["jitter_ratio"], 0.15)

  delay_ms =
    if exponential
      base * (2**(attempt_number - 1))
    else
      base
    end
  delay_ms = [delay_ms, max_d].min
  jitter = jitter_ratio.clamp(0.0, 1.0) * delay_ms * rand
  sleep((delay_ms + jitter) / 1000.0)
end