Module: OllamaAgent::Providers::ErrorClassifier

Defined in:
lib/ollama_agent/providers/error_classifier.rb

Overview

Maps raw HTTP errors and Ruby exceptions into the typed OllamaAgent error hierarchy so that the CredentialRouter can apply the correct cooldown and retry strategy without coupling to provider-specific error messages.

Classification rules (in priority order):

HTTP 401 / 403  → AuthenticationError   (permanent disable)
HTTP 402        → QuotaExhaustedError   (long cooldown)
HTTP 429 + quota phrasing → QuotaExhaustedError
HTTP 429 (plain)          → RateLimitError
HTTP 5xx        → TemporaryProviderError (brief cooldown)
Timeout / network → TemporaryProviderError
Unknown           → re-raised as-is

Constant Summary collapse

QUOTA_PHRASES =

Phrases that signal a long-term quota exhaustion rather than a short rate-limit window. Matched case-insensitively against error.message.

[
  "quota", "exceeded", "daily_limit", "monthly_limit", "weekly_limit", "billing", "insufficient_quota", "run out of credits", "weekly usage limit", "monthly usage limit", "exceeded your current quota", "you have run out"
].freeze

Class Method Summary collapse

Class Method Details

.classify(error, http_status: nil) ⇒ OllamaAgent::Error

Classify a raw error into a typed OllamaAgent error.

Parameters:

  • error (StandardError)
  • http_status (Integer, nil) (defaults to: nil)

    explicit HTTP status (overrides auto-extract)

Returns:



31
32
33
34
35
36
37
38
# File 'lib/ollama_agent/providers/error_classifier.rb', line 31

def classify(error, http_status: nil)
  status = http_status || extract_http_status(error)

  return classify_by_status(status, error) if status && !status.zero?
  return classify_network(error) if network_error?(error)

  error # pass through — caller should re-raise
end

.classify_by_status(status, error) ⇒ Object



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/ollama_agent/providers/error_classifier.rb', line 61

def self.classify_by_status(status, error)
  msg = error.message.to_s
  case status
  when 401, 403
    if msg.match?(/subscription/i)
      OllamaAgent::SubscriptionRequiredError.new(msg)
    else
      OllamaAgent::AuthenticationError.new(msg)
    end
  when 402
    OllamaAgent::QuotaExhaustedError.new(msg)
  when 429
    if quota_phrased?(msg)
      OllamaAgent::QuotaExhaustedError.new(msg)
    else
      OllamaAgent::RateLimitError.new(msg)
    end
  when 500..599
    OllamaAgent::TemporaryProviderError.new(msg)
  else
    error
  end
end

.classify_network(error) ⇒ Object



85
86
87
# File 'lib/ollama_agent/providers/error_classifier.rb', line 85

def self.classify_network(error)
  OllamaAgent::TemporaryProviderError.new(error.message)
end

.extract_http_status(error) ⇒ Object



89
90
91
# File 'lib/ollama_agent/providers/error_classifier.rb', line 89

def self.extract_http_status(error)
  error.message.to_s[/\b(\d{3})\b/, 1].to_i
end

.network_error?(error) ⇒ Boolean

Returns:

  • (Boolean)


98
99
100
101
102
103
104
# File 'lib/ollama_agent/providers/error_classifier.rb', line 98

def self.network_error?(error)
  error.is_a?(Timeout::Error)          ||
    error.is_a?(Errno::ECONNREFUSED)   ||
    error.is_a?(Errno::ECONNRESET)     ||
    error.is_a?(Errno::ETIMEDOUT)      ||
    (defined?(SocketError) && error.is_a?(SocketError))
end

.permanently_disabling?(error) ⇒ Boolean

Parameters:

  • error (StandardError)

Returns:

  • (Boolean)


42
43
44
# File 'lib/ollama_agent/providers/error_classifier.rb', line 42

def permanently_disabling?(error)
  error.is_a?(OllamaAgent::AuthenticationError)
end

.quota_exhaustion_message?(error) ⇒ Boolean

Parameters:

  • error (StandardError)

Returns:

  • (Boolean)


57
58
59
# File 'lib/ollama_agent/providers/error_classifier.rb', line 57

def quota_exhaustion_message?(error)
  quota_phrased?(error.message.to_s)
end

.quota_phrased?(msg) ⇒ Boolean

Returns:

  • (Boolean)


93
94
95
96
# File 'lib/ollama_agent/providers/error_classifier.rb', line 93

def self.quota_phrased?(msg)
  m = msg.to_s.downcase
  QUOTA_PHRASES.any? { |phrase| m.include?(phrase) }
end

.retryable_with_other_credential?(error) ⇒ Boolean

Parameters:

  • error (StandardError)

Returns:

  • (Boolean)


48
49
50
51
52
53
# File 'lib/ollama_agent/providers/error_classifier.rb', line 48

def retryable_with_other_credential?(error)
  error.is_a?(OllamaAgent::RateLimitError) ||
    error.is_a?(OllamaAgent::QuotaExhaustedError) ||
    error.is_a?(OllamaAgent::TemporaryProviderError) ||
    error.is_a?(OllamaAgent::SubscriptionRequiredError)
end