jeevesagent.governance.retry¶
Resilience for model calls.
Two pieces:
RetryPolicy— a small dataclass describing the backoff schedule (max attempts, initial delay, multiplier, max cap, jitter).classify_model_error()— inspects a raw exception from any model SDK and maps it to our taxonomy (TransientModelError/RateLimitError/AuthenticationError/ etc.). Lazy imports so we never require an SDK that isn’t installed.
The actual retry loop lives in
RetryingModel, which wraps any
Model and runs every call through this
policy + classifier pair. Splitting policy/classification from the
retry mechanics keeps each piece testable in isolation and lets
callers reuse the classifier for non-Agent code (e.g. cron jobs
that hit the same SDK).
Classes¶
Exponential-backoff-with-jitter retry schedule. |
Functions¶
|
Map an exception from any model SDK to the framework's taxonomy. |
|
Backoff (seconds) before retry number |
Module Contents¶
- class jeevesagent.governance.retry.RetryPolicy[source]¶
Exponential-backoff-with-jitter retry schedule.
The default is sensible for production: up to 3 attempts (one initial + two retries), starting at 1 s, doubling each attempt, capped at 30 s, with ±10% jitter so synchronised clients don’t reform a thundering herd.
Examples:
# default — sensible for most apps RetryPolicy() # disable retries (fail fast) RetryPolicy.disabled() # aggressive — survives long provider blips RetryPolicy.aggressive() # tuned to a specific SLO RetryPolicy(max_attempts=4, initial_delay_s=0.5, max_delay_s=15)
The schedule applies between attempts: the first call has no delay, the second is delayed by
initial_delay_s(± jitter), the third byinitial_delay_s * multiplier(± jitter), etc., each capped atmax_delay_s. Provider-suppliedRetry-Afterhints (carried onretry_after) override the computed delay when they ask for more time — we never sleep less than the provider asked for.- classmethod aggressive() RetryPolicy[source]¶
Up to 6 attempts, faster initial backoff, longer cap. Use when the underlying provider is known-flaky and the caller prefers slow success over fast failure.
- classmethod disabled() RetryPolicy[source]¶
Single attempt, no retries — fail fast on any error.
- initial_delay_s: float = 1.0¶
Backoff before the FIRST retry (i.e. between attempts 1 and 2). Subsequent retries use
initial_delay_s * multiplier**n.
- jitter: float = 0.1¶
Fractional ±jitter applied to each computed delay.
0.1= ±10%. Set to0for deterministic backoff (useful in tests).
- max_attempts: int = 3¶
Maximum total attempts including the first call.
1means no retries; the call either succeeds or raises immediately. The minimum-meaningful retry policy is thereforemax_attempts=2.
- jeevesagent.governance.retry.classify_model_error(exc: BaseException) jeevesagent.core.errors.ModelError | None[source]¶
Map an exception from any model SDK to the framework’s taxonomy.
Returns
Nonewhen the exception is not recognised as a model-call failure — let callers decide whether to wrap it in something else or propagate. Returns an instance of one ofTransientModelError/RateLimitError/AuthenticationError/InvalidRequestError/ContentFilterError/PermanentModelErrorotherwise.SDK imports are lazy — having e.g. the
anthropicpackage installed is not required for OpenAI classification to work, and vice versa.
- jeevesagent.governance.retry.compute_backoff(policy: RetryPolicy, attempt: int, *, retry_after: float | None = None, rng: random.Random | None = None) float[source]¶
Backoff (seconds) before retry number
attempt(1-indexed).attempt=1is the delay before the first retry (i.e. between attempts 1 and 2 ofmax_attempts). Returns0whenpolicyis disabled.retry_after(provider hint, e.g. from a 429Retry-Afterheader) acts as a floor: we never wait less than the provider asked for, but we still cap atpolicy.max_delay_s. This means a provider-supplied 60-second hint paired with a 30-second cap is honoured at 60 seconds (exceeding the cap on purpose — the provider is more authoritative than our heuristic).