Repository navigation
[AISAGE-759] feat(ai-gateway): rate-limit requests per ChatGPT connection - #8559
chrarnoldus wants to merge 2 commits into
Conversation
Count requests served through a ChatGPT connection against a Vercel Firewall rule keyed on the connection, like the per-account free model limit. Every connection shares the partner project's OpenAI rate limits, so one connection driven by a relay could exhaust them for everyone else.
Code Review SummaryStatus: No Issues Found | Recommendation: Merge Executive SummaryReviewed the incremental commit Assumptions: Files Reviewed (2 files)
Previous Review Summary (commit 9ee7af8)Current summary above is authoritative. Previous snapshots are kept for context only. Previous review (commit 9ee7af8)Status: No Issues Found | Recommendation: Merge Executive SummaryReviewed the per-connection ChatGPT rate limit in the five changed files: the check runs on the only code path that can select an Assumptions: Files Reviewed (5 files)
Reviewed by deepseek-flash-latest · Input: 22.8K · Output: 1.4K · Cached: 154.1K Review guidance: REVIEW.md from base branch |
Summary
This adds a per-connection rate limit to the "Sign in with ChatGPT" route (
openai-chatgptprovider). It works like the per-account free-model limit from #8456.Why. Every ChatGPT connection shares the partner project's OpenAI rate limits. A single connection driven by an automated relay can use them up, and then every other person on the route gets OpenAI rate-limit errors.
How it works:
openai-chatgpt/rate-limit.tscounts the request against the Vercel Firewall ruleopenai-chatgpt-inferencethrough the sharedisFirewallRateLimitedhelper, the same wayfree-model-rate-limit.tsdoes.<kiloUserId>:personalfor a personal connection<kiloUserId>:<orgId>for an organization member's connectionshared-services:<orgId>for an organization's shared-services connectionhandleLlmProxyRequestruns the check right aftergetProvider, and only when the selected provider carries a ChatGPT connection owner. Other providers are never counted.429 rate_limit_exceededwithx-should-retry: false, like the free-model limit.Tracked in AISAGE-759.
Deployment
Create a Vercel Firewall rule on
kilocode-ai-gatewaybefore this takes effect:@vercel/firewall, rate limit IDopenai-chatgpt-inference.rateLimitKey= the connection owner). The dashboard key choice does not matter.Before the rule exists:
checkRateLimittreats an unknown rule as not rate limited, so this change limits nothing.isFirewallRateLimitedalso reports the missing rule to Sentry (source: openai_chatgpt_inference), throttled to once a minute per instance.Why these values. In the last 7 days, the busiest IP using the genuine Kilo client (
Kilo-Code/… ai-sdk/…) on this route sent at most 871 requests in an hour and 364 in 10 minutes. Several users can share one IP, so these are upper bounds per connection. Neither limit would have refused a genuine Kilo request in the past day. The detailed figures are in AISAGE-759.Per-region counters. Vercel counts each region separately, so a connection that is served by both
fra1andsfo1can get up to twice the limit.Retry headers. The refusal sends
x-should-retry: false, like the free-model limit. With a window of 10 minutes or longer, an SDK's automatic retries (seconds of backoff) all fail anyway and only spend more of the allowance. Vercel does not report when a window resets, so no accurateretry-afteris available. The code comments now require the window to stay at 10 minutes or longer.Verification
openai-chatgpt/rate-limit.test.ts. It checks the rule id and the bucket keys for personal, organization-member and shared-services connections.llm-proxy.test.tscases for three paths:x-should-retry: falseand makes no upstream call;openai-chatgpt/,handlers/,typesafe/and free-model rate-limit suites; all pass.pnpm --filter @kilocode/web-shared typecheckand oxlint on the changed files; both are clean.checkRateLimitonly works on deployed Vercel infrastructure.Visual Changes
N/A
Reviewer Notes
getProvider, because the connection owner is only known once the ChatGPT route has been chosen. Choosing the route includes resolving the delegated token, so an over-limit request still pays for that lookup. A cheaper check before routing would have to key on the account instead of the connection.gateway-inferencelimit, keyed on the account, still applies first. This rule is a tighter, connection-scoped bucket on top of it.