Repository navigation
fix(sdk/python): honor numeric Retry-After minimum waits - #1129
Conversation
There was a problem hiding this comment.
Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.
An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.
Performance
✓ No regressions detected |
📊 Coverage gateThresholds from
✅ Gate passedNo surface regressed past the allowed threshold and the aggregate stayed above the floor. |
📐 Patch coverage gateThreshold: 80% on lines this PR touches vs
✅ Patch gate passedEvery surface whose lines were touched by this PR has patch coverage at or above the threshold. |
santoshkumarradha
left a comment
There was a problem hiding this comment.
Looks good. The retry delay now honors a valid server cooldown without breaking the normal backoff path, and the focused tests cover both valid and invalid values.
Treating every finite Retry-After as a minimum let a provider suspend each retry indefinitely: a 86400s hint made the default five retries sleep five days, with no outer deadline on direct Agent.ai calls. Honour hints up to max(rate_limit_max_delay, 300s) and clamp anything larger to that ceiling, so jitter still never retries before the (capped) cooldown. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Pushed one commit on top since this had been waiting a few days. Treating a valid Retry-After as a minimum is right, but nothing bounded it: |
AbirAbbas
left a comment
There was a problem hiding this comment.
Re-approving after the Retry-After ceiling commit (my push dismissed the earlier approval). Without the ceiling, the new cases fail with 3600s and 4500s sleeps. The full Python suite (2931 passed) and ruff 0.15.22 are clean, and CI is green.
Summary
The Python SDK can retry before a provider's numeric
Retry-Aftercooldown ends: the default jitter can turn a 10-second hint into 7.5 seconds, and hints aboverate_limit_max_delayare discarded. Treat finite positive hints as minimum waits, retaining jitter without retrying early; invalid hints fall back to ordinary exponential backoff.This deliberately allows a provider-requested wait above the local exponential-backoff cap. The configuration description now makes that distinction explicit. Five parameterized regression cases exercise early retries, above-cap hints, and negative/NaN/infinite hints.
Type of change
Test plan
Executed the five test stages from
scripts/test-all.shindividually, split across macOS (Python/Node) and the existing Linux Go environment; this is not a claim that one invocation of the script passed on macOS.python -m pytestwith the unchanged default coverage/marker configuration — 2,809 passed, 4 skipped, 38 deselected; displayed aggregate coverage 95%. This full run preceded an AST-identical formatter-only commit; 28 rate-limiter/config tests passed again on the final commit.go test ./...in both modules, Linux arm64 / Go 1.25.14,GOFLAGS="-tags=sqlite_fts5 -p=2"; both passed.go mod tidy -diffproduced no changes.CI=1 npm run test:core— 1,256 passed, 1 skipped.CI=1 npm run test— 837 passed.Linux checks ran as a non-root user with real DNS packets forwarded over certificate-validated HTTPS because this host rewrites reserved domains. The Go SDK used a complete writable temporary module copy whose 220 files matched the final commit; no test assertions, timeouts, or Go source overlays were changed. Earlier executor setup failures were corrected before the successful runs.
One earlier full Python run also hit an unrelated existing 1-second harness timeout. Focused, module, collection-prefix, and the latest full run passed unchanged; its root cause remains unproven.
Test coverage
Checklist
Related issues / PRs
Related context: #265 established the local backoff cap; #1078 isolated the jitter RNG. This change preserves the private RNG and clarifies how provider cooldowns interact with the cap.