Module: Aireview::LlmFailure

Defined in:
lib/aireview/llm_failure.rb

Overview

Classifies an LLM request error. Answers only "what is it"; the decision to retry, switch the key or the model belongs to LlmRouter.

:daily_quota — the project's daily quota for the model, retries are useless; :rate_limit — a per-minute limit, passes after the hinted time; :overloaded — 503 / "high demand" on the model; :timeout — no answer for longer than LLM_TIMEOUT; :unavailable — the provider has no such model: retired, a typo, not pulled into Ollama; :fatal — an API error that reserves do not cure; :unhandled — not a provider error, re-raised as is.

Constant Summary collapse

KINDS =
i[daily_quota rate_limit overloaded timeout unavailable fatal unhandled].freeze
UNAVAILABLE_MODEL_TEXT =

Only by the provider's text about the model: a bare 404 is also what a wrong LLM_API_BASE or proxy answers, and the next model will not help. Ollama: model 'x' not found (through /v1) and model "x" not found, try pulling it first (older versions and /api).

Regexp.union(
  /\bmodels?\/[\w.:-]+ is not found\b/i,
  /\bis not supported for generateContent\b/i,
  /\bmodel ['"][^'"]+['"] not found\b/i
)
QUOTA_FAILURE_TYPE =
'type.googleapis.com/google.rpc.QuotaFailure'
DAILY_QUOTA_ID =
/PerDay/i
DAILY_QUOTA_TEXT =
/\bper\s+day\b|\bdaily\b/i
RETRY_AFTER =
/retry\s+(?:in|after)\s+(\d+(?:\.\d+)?)\s*(?:s|sec|secs|second|seconds)\b/i

Class Method Summary collapse

Class Method Details

.classify(error) ⇒ Object

Quota details are checked before the exception class: RubyLLM turns a 429 mentioning input_token into ContextLengthExceededError, although it is an exhausted token quota, not an oversized request.



37
38
39
40
41
42
# File 'lib/aireview/llm_failure.rb', line 37

def classify(error)
  return :timeout if transport_timeout?(error)
  return :unhandled unless ruby_llm_error?(error)

  quota_kind(error) || model_kind(error) || (overloaded?(error) ? :overloaded : :fatal)
end

.retry_after_seconds(message) ⇒ Object



99
100
101
102
# File 'lib/aireview/llm_failure.rb', line 99

def retry_after_seconds(message)
  match = message.to_s.match(RETRY_AFTER)
  match[1].to_f if match
end