Retry, backoff and default Generate timeout #48

4 Commits
Author SHA1 Message Date
dev_agentandClaude Opus 5.5 f8e975e284 Do not retry an HTTP 408; lock retry cap and timeout values
CI / ci (push) Successful in 1m30s
Independent review Codex gpt-6-sol high: APPROVED (0 findings)
CI / ci (pull_request) Successful in 1m30s
The OpenAI and Anthropic adapters now report an HTTP 408 as
llm.TimeoutStatusError, which still matches llm.ErrTimeout but carries
its status. Retrying no longer retries any error carrying a 4xx status,
so a vendor's 408 is returned at once while a transport timeout, which
has no status, is still retried.

Tests: 408 (bare and wrapped) is not retried and a transport timeout is;
FromSettings integration cases for an OpenAI and Anthropic 408 and an
OpenAI transport timeout; the cap and default-timeout tests assert the
literal 20 s and 60 s instead of the constants they lock.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 10:58:59 -04:00
dev_agentandClaude Opus 5.5 d90886ddc2 Bound whole retrying Generate call by one deadline
CI / ci (push) Successful in 1m29s
CI / ci (pull_request) Successful in 1m33s
Request.Timeout, or the 60-second default, now sets a single context
deadline covering every attempt and wait, instead of restarting for
each attempt. A shorter caller deadline still wins; attempts receive
Timeout 0 so adapters do not restart the clock. A negative Timeout is
left for the wrapped Provider to reject with its key redaction.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 10:53:53 -04:00
dev_agentandClaude Opus 5.5 bcdea85a2d Wire retrying Provider into presets.FromSettings
CI / ci (pull_request) Successful in 1m31s
CI / ci (push) Successful in 1m32s
FromSettings now returns llm.NewRetrying around the configured adapter,
so every Provider it builds retries transient Generate failures and gets
the default timeout; ListModels and Verify pass through.

The test recording transport now answers 400 instead of failing the
round trip: the ollama adapter reports a transport failure as
ErrTimeout, which is retried, so the helper would see three requests.

Tests: a 429 then 200 succeeds on the second request; exhausted retries
return ErrProvider after MaxRetries+1 requests with no key in any error.

Maestro task: 1a882923-fdb4-4576-ab82-9529e9974b26

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 10:49:46 -04:00
dev_agentandClaude Opus 5.5 cbf24e63e1 Add retrying Provider wrapper with backoff and default timeout
llm.NewRetrying wraps a Provider and retries ErrRateLimited, ErrTimeout
and 5xx ErrProvider at most twice. A rate limit waits RetryAfter, capped
at 20 s; other retries use jittered exponential backoff. ErrAuth, 4xx and
other errors are never retried, and no retry is made whose wait would not
end before the caller's context deadline. Generate gets a 60 s per-attempt
timeout when Request.Timeout is 0.

Maestro task: 1a882923-fdb4-4576-ab82-9529e9974b26

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 10:48:07 -04:00