A lightweight reverse proxy that intercepts NVIDIA API calls and applies sliding-window RPM enforcement + sequential holdout pacing to stay within NVIDIA rate limits. Includes a real-time WebSocket dashboard.
- Sliding-Window RPM Enforcement: Enforces a true 60s rolling window (default 40 RPM to match NVIDIA free tier). The
--rpmflag actually controls the limit — not just cosmetic - Completion-Based Holdout: Secondary pacing engine that enforces a configurable cooldown gap (default 1.67s) between request completions, smoothing burst edges
- Strict Sequential Locking: One request active at a time — the lock is held for the entire request lifecycle including streaming response
- 429 Retry Logic: Exponential backoff (up to 5 retries, capped at 30s) on NVIDIA rate-limit responses — re-checks holdout before each retry
- Context Pruning (Opt-in): Optionally prune chat history to stay under token limits — opt-in via
--no-context-pruning(default: on with 160K ceiling) - Connection Pooling: Shared HTTP client with keepalive for fast TLS reuse
- Real-time Dashboard: Dark-themed web UI with live stats, queue, and request log via WebSocket at
http://127.0.0.1:8000/ - Request Queuing: Requests wait in a FIFO queue behind the sequential lock
- Live Statistics: Track total, successful, rate-limited, failed, network-retried, and context-pruned requests
- Per-Request Timestamps: Dashboard shows
request_sent_timeandrequest_complete_timefor debugging pacing gaps - Client Disconnect Guard: Graceful handling of early client disconnects without blocking the pacing engine
pip install fastapi uvicorn httpx truststore certifi python-multipart websockets
truststorelets the proxy verify TLS using the OS (Windows) trust store. This is required on machines where antivirus/corporate software (e.g. AVG Web/Mail Shield) intercepts HTTPS and re-signs certs with a private root CA that OpenSSL/certifi reject.
python nvidia_proxy.pypython nvidia_proxy.py --rpm 40python nvidia_proxy.py --rpm 40 --port 8000 --host 127.0.0.1 --timeout 500 --cooldown 1.0Context pruning is enabled by default (ceiling: 160K tokens) to keep chat history manageable. Disable it when message role integrity is critical:
# Disable context pruning
python nvidia_proxy.py --no-context-pruningWhy disable? Aggressive truncation can split
assistanttool-call messages from their correspondingtoolresponses, causing NVIDIA to reject the request withUnexpected role 'tool' after role 'system'.
| Argument | Short | Default | Description |
|---|---|---|---|
--rpm |
-r |
40 | Max requests per rolling 60s window |
--port |
-p |
8000 | Port to run the proxy on |
--host |
127.0.0.1 | Host to bind to | |
--timeout |
-t |
500 | Upstream timeout in seconds |
--cooldown |
-c |
1.67 | Post-completion holdout buffer (seconds) |
--max-context-tokens |
160000 | Token ceiling for context pruning | |
--keep-last-messages |
30 | Messages to preserve when pruning | |
--no-context-pruning |
Disable context pruning |
If you authenticated NVIDIA via opencode auth login, OpenCode already has a
built-in nvidia provider pointing at https://integrate.api.nvidia.com/v1. You
only need to override its baseURL to send traffic through the proxy — models
and the API key are inherited. Edit ~/.config/opencode/opencode.jsonc:
Restart OpenCode after editing this file so the new baseURL takes effect. Verify interception by watching the proxy console — every forwarded call prints
[proxy] intercepted POST /v1/chat/completions.
Access the dashboard at: http://127.0.0.1:8000/
The dashboard displays:
- Rate limit configuration and current RPM
- Concurrency status (e.g.,
2 / 3concurrent requests) - Total, successful, rate-limited, failed, and context-pruned requests
- Request queue with waiting requests
- Recent API calls with status, wait time, and timestamps
- Intercept: OpenCode sends requests to the local proxy instead of directly to NVIDIA
- Queue: Requests enter a FIFO queue behind the sequential lock
- RPM Gate:
enforce_rate_limit()checks a sliding window of forwarded request starts — ifRATE_LIMIT_REQUESTSstarts exist in the last 60s, it delays until a slot opens - Holdout Gate:
enforce_completion_holdout()checks the elapsed time since the last response stream closed — if less thanCOOLDOWN_BUFFER(default 1.67s), it sleeps the difference. This smooths burst edges - Forward: Approved requests stream to the NVIDIA API with 429 retry logic (exponential backoff, up to 5 retries, 30s cap)
- Track Completion: When the upstream response stream fully closes, the completion timestamp is recorded, enabling the next request's holdout calculation
- Dashboard: All stats are pushed to the browser dashboard via WebSocket every second
OpenCode → Queue → Sequential Lock → RPM Window → Holdout Gate → NVIDIA API
↓
deque of start timestamps
(60s rolling)
# Default (40 RPM, matches NVIDIA free tier)
python nvidia_proxy.py
# Conservative (lower RPM for safety margin)
python nvidia_proxy.py --rpm 30 --cooldown 2.0
# Tighter cooldown + max RPM (higher 429 risk)
python nvidia_proxy.py --rpm 40 --cooldown 1.0Run the automated setup script as Administrator:
initial_setup.batThis will:
- Check/install Python dependencies
- Test and fix certificate issues (auto-detects AVG, other AVs)
- Configure OpenCode to use the proxy
- Start the proxy service
- Create a log file (
initial_setup.log) for debugging
Logs are reset each run. Check initial_setup.log if something fails.
If the proxy fails with SSL errors (e.g., SSL: CERTIFICATE_VERIFY_FAILED), your antivirus is intercepting HTTPS traffic. You need to add its root certificate to the Windows trust store.
Run initial_setup.bat as Administrator — it will attempt to auto-detect and import common antivirus certificates (AVG, etc.).
-
Export the AVG root certificate:
- Open AVG Settings → General → Manage exceptions
- Or search Windows for "AVG certificate export"
- Save as
.crtfile (e.g.,avg_root_ca.crt)
-
Import to Windows Root store:
:: Run as Administrator certutil -addstore Root "C:\Users\YourUsername\avg_root_ca.crt"
-
Verify it works:
python -c "import httpx, truststore, ssl; ctx = truststore.SSLContext(ssl.PROTOCOL_TLS_CLIENT); print(httpx.get('https://integrate.api.nvidia.com/', verify=ctx).status_code)"
| Antivirus | Possible Certificate Locations |
|---|---|
| AVG | C:\Program Files\AVG\, C:\ProgramData\AVG\ |
| Avast | C:\Program Files\Avast\, C:\ProgramData\Avast\ |
| Kaspersky | C:\Program Files\Kaspersky Lab\ |
| Norton | C:\Program Files\Norton\ |
Search for .crt or .cer files in the antivirus installation directory.
Edit ~/.config/opencode/opencode.jsonc:
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"nvidia": {
"options": {
"baseURL": "http://127.0.0.1:8000/v1"
}
}
}
}Restart OpenCode GUI for changes to take effect.
:: Install dependencies
pip install fastapi uvicorn httpx truststore websockets
:: Run proxy (default ~36 RPM, sequential)
python nvidia_proxy.py
:: Or with custom settings
python nvidia_proxy.py --rpm 30 --port 8000 --host 127.0.0.1 --cooldown 2.0- Dashboard: http://127.0.0.1:8000/
- Test API: http://127.0.0.1:8000/v1/models
- Fixed (CRITICAL — slip): Added a send-side floor. Spacing was enforced only off the completion event; if completion tracking was ever disturbed (a cancelled stream, an error path), two requests could hit NVIDIA inside the 1.67s window.
wait_for_holdout()now enforces three gates: (1) previous stream finished, (2) ≥cooldown since previous completion, (3) ≥cooldown since previous send. Gate 3 makes the 1.67s spacing impossible to bypass. - Fixed (CRITICAL — hang/leak): The
relay()finallydidawait upstream.aclose()/await release_slot_and_decrement()before re-opening the pacing gate. When a client aborted a stream mid-flight, theCancelledErrorcould interrupt those awaits and skipstream_complete_event.set(), wedging the gate (or leaking the concurrency slot). The critical section is now fully synchronous (release_slot_sync()+ gate re-open) with awaitable cleanup moved last. - Fixed: Cancelled/errored requests now release the concurrency slot via a guaranteed
finally, so the slot can never leak. - Fixed:
holdout_compliantwas tautologically alwaystrue(it measured the proxy's own computed gap). It now measures the real wall-clock gap between consecutive sends — so the dashboard's "Holdout FAIL" counter can actually surface a slip, and the console prints a!! SPACING VIOLATIONline if one ever occurs. - New: Full timestamped console tracing. Every request prints
RECEIVED → [holdout] → SEND (with gap_since_prev_SEND / gap_since_prev_COMPLETION) → RECV status → COMPLETED (duration). Run the proxy in its own window to watch real pacing.
- Fixed: 429 retries now re-check holdout before each attempt — previously bursts could trigger more 429s
- Fixed: All error paths (client disconnect, exception, 4xx, 429 exhaustion) now set
request_complete_timebefore releasing resources - Fixed: OPTIONS preflight requests no longer counted in stats
- New: Shared HTTP connection pool — reuses TLS connections for faster requests
- New: Dashboard exposes
request_sent_timeandrequest_complete_timeper request for debugging - Improved: Slot/release ordering — timestamps set BEFORE releasing slot and lock for accurate accounting
- Fixed (CRITICAL): Holdout was setting
last_completion_timeBEFORE request started. Now returns arecord_completion()callback that sets the timestamp only AFTER the response stream fully completes — guarantees 1.67s gap between actual completions.
- Fixed:
SEQUENTIAL_LOCKnow wraps the entire request lifecycle (acquired withasync with). Previously released after forwarding, allowing concurrent requests to bypass the cooldown buffer.
- Fixed: Rate limit window now records requests after successful send (not before). Previously, 429 retries consumed window slots, causing artificial rate limiting.
- New: Retry-After header parsing — respects NVIDIA's specified wait time instead of using only exponential backoff.
- New: Network error retries — automatically retries
ConnectError,ConnectTimeout,NetworkError, andSSLErrorup to 3 times with exponential backoff (max 10s). - Improved: 429 retry logic now separates rate-limited vs. network failures, with better logging showing attempt counts.
- Improved: Error messages now include exception type and details for easier debugging.
- Fixed:
content-lengthheader now forwarded to upstream (improves compatibility with some endpoints).
- New:
--rpmflag now enforces a real 60s sliding window instead of being cosmetic. Requests are delayed when the window is full. - New:
--cooldownflag made configurable via CLI (was hardcoded). - Changed: Default RPM from 30 → 40 to match NVIDIA free tier limit.
- Fixed: Pacing holdout now uses elapsed-time checks (
now - last_completion_time) instead of future-wall-clock projection. Previously, the relay's completion handler would overwrite the forward-projected holdout time, collapsing the cooldown gap after long requests. - Fixed:
stats["rate_limited_requests"]counter is now incremented on each 429 retry (was stuck at 0). - Fixed:
estimate_tokens()now handles multi-modal content arrays (contentas a list, not just a string). - Fixed:
response_timeis now populated for all request outcomes (success, failure, disconnect). - Removed: Dead
finalisedvariable, deadRATE_LIMIT_WINDOW_SECONDSconstant.
MIT
{ "$schema": "https://opencode.ai/config.json", "provider": { "nvidia": { "options": { "baseURL": "http://127.0.0.1:8000/v1" } } } }