anomalyco / anomalyco/opencode
[FEATURE]: Per-Provider Quota-Aware Auto-Retry with Configurable Reset Schedule
@jlongster is already working on this.
Since Aug 19, 2026.
- Dominant language
- TypeScript
- Stars
- 209k
- Forks
- 27.5k
- PR merge metrics
- PR metrics pending
Description
Feature hasn't been suggested before.
- I have verified this feature I'm about to request hasn't been suggested before.
Describe the enhancement you want to request
Problem
OpenCode's session retry already parses retry-after headers and recognises FreeUsageLimitError / GoUsageLimitError (see packages/opencode/src/session/retry.ts), but the handling is essentially hardcoded to the OpenCode Go subscription:
GoUsageLimitErroralready extractsmetadata.limitName("5 hour" | "weekly" | "monthly") andretry-after, then surfaces it in the UI as "X hour usage limit reached. It will reset in Y hours." — but the session does not actually wait for that reset; it just retries up to 5 times with exponential backoff.- Providers other than OpenCode Go (e.g. users bringing their own keys to fixed-window-quota providers) hit a 429 with no
metadata.limitNamein the body. The retry logic falls back to exponential backoff, exhausts the 5 attempts, and gives up — exactly when the user is most likely to need an automatic wait-and-resume.
In short: OpenCode already has the display half of quota handling (for Go) but not the wait-until-reset half, and the whole thing is only wired up for Go.
Proposed solution
- Generalise the existing quota classification.
packages/opencode/src/session/retry.tsalready has the primitives (LimitName = "5 hour" | "weekly" | "monthly",retry-afterparsing). Expose them through a per-provider config so any provider can declare its own reset schedule. - Read the schedule from
provider.<id>.quota, notprovider.options.quota. Theoptionsblock is pass-through to the AI SDK (timeout,chunkTimeout,setCacheKey,baseURL,apiKey,headers); quota / retry are OpenCode-internal behaviour, so they belong next tooptionsrather than inside it. - Actually wait for the next reset instead of giving up after 5 exponential attempts.
Config (extends the existing provider block; field names follow the camelCase convention used by baseURL, chunkTimeout, setCacheKey):
{
"provider": {
"<id>": {
"options": { "...": "..." },
"quota": {
"resetTimes": ["00:00", "05:00", "10:00", "15:00", "20:00"],
"weeklyResetDay": "monday",
"monthlyResetDay": 1
},
"retry": {
"maxRetriesPerWindow": 5,
"maxTotalRetries": 50
}
}
}
}
Behaviour when a quota error is hit:
- Classify error → 5h / weekly / monthly / transient (reuse the existing
LimitNametypes fromretry.ts). - 5h hit → next reset from
resetTimes, sleep, resume. - Weekly / monthly hit → surface a clear "X limit reached, resets on …" message; no auto-retry inside the session.
- After
maxRetriesPerWindowfailures inside one window, queue for the next window. - Hard ceiling
maxTotalRetriesprevents runaway sessions.
Backwards compatibility: providers without a quota block fall back to today's behaviour (exponential backoff, 5 attempts).
Related issues
- #43126 — auto pause/resume on known reset time (closest match — semantic of "wait for the right reset" already exists, but no per-provider schema)
- #39790 / #39791 — fixed-window quota should not retry blindly
- #32423 — provider-specific rate limiting (RPM throttle, orthogonal)
- #37412 —
ProviderConfig.options.maxRetries/...proposal (this extends that schema by addingprovider.quota/provider.retryat the top level) - #21960 / #17648 / #30510 / #41848 — retry has no max attempt count
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.