feat(provider): track and learn per-provider rate limits#1
Merged
Conversation
Adds RateLimit module that ticks on every outbound request, parses any known rate-limit response headers (x-ratelimit-*, anthropic-ratelimit-*, IETF ratelimit-*), and on the first 429 from a provider, writes the observed per-minute and per-day counts to opencode.json under provider.<id>.options.rateLimit. This gives proxies like the RWTH Aachen API — which do not expose rate-limit headers — a persisted limit after the first hit.
- Inline minute/day cutoffs per style guide. - Deduplicate the parsed-headers object construction. - Drop the existsSync TOCTOU in readJsonSafe; handle ENOENT from readFileSync instead.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
RateLimitmodule (packages/opencode/src/provider/rate-limit.ts) that ticks on every outbound request and parses standard rate-limit response headers (x-ratelimit-*,anthropic-ratelimit-*, IETFratelimit-*) when providers expose them.429from a provider, writes the observed per-minute and per-day request counts to~/.config/opencode/opencode.jsonunderprovider.<id>.options.rateLimit. Values only bump upward, so retry-induced floods don't lower a learned limit.opencode.jsoncis present, to avoid clobbering user comments.ConfigProvider.Info.optionswith a typedrateLimit: { perMinute?, perDay? }field, so users can also set limits by hand.infolevel, which makes it easy to confirm what a proxy like RWTH Aachen returns without adding any provider-specific code.Motivation: proxies such as the RWTH Aachen OpenAI-compatible API do not surface rate-limit headers, so the client has no way to know the limit until a 429 lands. This gives all providers — RWTH and any other header-less proxy — a learned, persisted limit after the first hit.
Test plan
bun typecheckinpackages/opencode— cleanbun test test/rate-limit.test.ts— 5/5 passx-ratelimit-*familyopencode.jsonononRateLimitError.jsonc-present guard skips the write~/.local/share/opencode/log/for the"provider first response headers"entry to confirm whether RWTH exposes any rate-limit headers.provider.<id>.options.rateLimit.perMinuteis written as N inopencode.json.https://claude.ai/code/session_01Ko79DH9kwztGCe8hQjbvfr