btcs-ai-rate-limits
v0.2.4
Published
OpenCode TUI sidebar for Azure API Management LLM quota usage.
Readme
btcs-ai-rate-limits
OpenCode TUI sidebar plugin for hourly Azure API Management LLM token quotas.
btcs-ai-rate-limits reads the usage state written by @jonab/azure-ai-sdk from:
macOS/Linux: $XDG_STATE_HOME/btcs-ai-rate-limits/quota.json
Windows: %LOCALAPPDATA%\btcs-ai-rate-limits\quota.json
(or ~/.local/state/btcs-ai-rate-limits/quota.json on macOS/Linux)On Windows, paste %LOCALAPPDATA%\\btcs-ai-rate-limits into File Explorer's
address bar. The TUI plugin creates the directory and an empty quota.json
when it starts. The SDK also creates it when handling a model response, even
when APIM does not send quota headers. Quota cards appear only when APIM
includes x-quota-tokens-remaining in its response.
Install
Add the package to the global OpenCode TUI configuration at
%USERPROFILE%\\.config\\opencode\\tui.json on Windows or
~/.config/opencode/tui.json on macOS/Linux:
{
"$schema": "https://opencode.ai/tui.json",
"plugin": [
["btcs-ai-rate-limits", { "order": ["opus", "terra", "sonnet"] }]
]
}TUI plugins must be registered in tui.json; OpenCode's opencode.json
plugin field is reserved for server/runtime plugins.
Restart OpenCode after installing or changing the plugin configuration.
Options
order: ordering for finite quota cards. Unlisted models follow alphabetically.collapsed: initial collapsed state. A user click persists the later choice.
Behavior
- Shows only models with nonzero usage in the current fixed UTC hour.
- Clears stale cards at the UTC-hour boundary and counts down to the next reset.
- Renders finite quotas with a green-to-yellow-to-orange-to-red block gradient.
- Groups unlimited models beneath finite quota cards with separate all-token and APIM-observed metrics.
How the numbers are derived
spent comes solely from the gateway: quota - remaining, so
spent + remaining == quota always holds. The card recomputes it on read, so a
state file from an older SDK cannot display a figure that breaks the invariant.
The gateway's x-quota-tokens-remaining is pre-deduction — the APIM policy
sets estimate-prompt-tokens="false", so the header describes the counter
before the current request is charged. The SDK subtracts x-tokens-consumed to
get the true figure, which is exact and needs no estimation.
All tokens N is the sum of all token categories reported in the model
responses. This is the number intended to reconcile with Grafana. APIM quota
is the separate shared-counter reading used for rate-limit enforcement, and
APIM observed N is the local sum of APIM x-tokens-consumed headers. Both APIM
figures are retained for diagnosis, but they are not the Grafana usage number.
Anthropic models use the APIM-observed total as the primary rate-limit/Grafana comparison number. Anthropic provider usage reports cache fields separately, so their provider total is shown only as a diagnostic and is not used as the primary rate-limit usage figure.
Shared limits
The gateway keys its counter on the quota amount, not the model, so models
with the same hourly quota drain one another — luna and deepseek-v4-flash
share one bucket, and deepseek-v4-pro shares 20,000,000 with any unrecognised
model. Cards stay per model and show shares with ... when a sibling draws on
the same counter.
Two limit families
The hourly token quota (APIM policy) drives the cards. A separate per-minute
deployment rate limit is recorded from the x-ratelimit-* headers. Both can
throttle independently.
