Skip to content

feat(providers): fill rate-limit gaps in the providers overview - #1157

Merged
Wibias merged 11 commits into
lidge-jun:devfrom
Wibias:feat/provider-rate-limits
Aug 7, 2026
Merged

feat(providers): fill rate-limit gaps in the providers overview#1157
Wibias merged 11 commits into
lidge-jun:devfrom
Wibias:feat/provider-rate-limits

Conversation

@Wibias

@Wibias Wibias commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

Summary

The providers overview ("Rate limits" section) only showed live utilization bars for the ~5 providers that have quota probes (openai, xai, anthropic, cursor, kimi, google-antigravity, a6api). Every other provider — plain API-key providers, local runtimes, free tiers — showed "No rate-limit data yet".

This PR fills the gaps with a two-layer approach: live probes where a real usage/balance endpoint exists, and documented reference limits (from official docs) for the rest.

1. Live quota probes (src/providers/quota.ts)

New probes wired into maybeFetchProviderQuota, following the existing probe contract (canonical-host guard before sending credentials, redirect: "error", 8s timeout, 4xx except 408/429 → terminal, 5xx/network → transient):

  • openrouterGET /api/v1/key: renders a credit window against the per-key spending cap (limit / usage / limit_remaining). No cap configured → no bar (falls back to documented reference).
  • deepseekGET /user/balance: renders a balance window against the granted allowance (total_balance / granted_balance). Top-up-only accounts (granted = 0) → no bar.

2. Documented reference limits (src/providers/registry.ts)

New rateLimits field on ProviderRegistryEntry (rpm / tpm / rpd / freeTier / source / updatedAt), populated for providers with public rate-limit docs:

Provider rpm / tpm / free-tier
groq 30 rpm / 6K tpm / 1K rpd
google (gemini) 15 rpm / 250K tpm / 1K rpd (free tier)
deepseek 30 rpm
cerebras 30 rpm / 30K tpm
together 60 rpm / 1M tpm
fireworks 600 rpm / 150K tpm
openrouter 20 rpm (free models)
zai 60 rpm / 1M tpm
minimax / minimax-cn 100 rpm / 200K tpm
mistral 5 rpm / 20K tpm (free tier)
sambanova / nebius / deepinfra free tiers
ollama / vllm / lm-studio local — no remote limits
opencode-free ~200 req / 5h

Threaded through derive.ts presets and /api/providers → GUI.

3. GUI display (bars + reference)

  • New ProviderDocumentedLimits renderer — shows the documented numbers as reference text (never as live utilization).
  • Dashboard: new "Documented" section listing providers with reference limits but no live bar; live-bar providers unchanged.
  • Per-provider overview: shows documented reference alongside (or instead of) the live bars.
  • New i18n strings in all six locales.

Tests

  • tests/provider-quota.test.ts: 9 new tests (openrouter + deepseek happy paths, canonical-host guards, no-cap/no-grant drops, terminal vs transient).
  • tests/provider-registry-parity.test.ts: rate-limit entries must carry source + updatedAt; presets round-trip.
  • gui/tests/provider-capacity.test.ts: formatDocumentedLimits pure formatting.
  • Full affected suites: 141 tests pass.

Summary by CodeRabbit

  • New Features
    • Added documented rate-limit details, including request, token, and daily quotas, free-tier notes, sources, and update dates.
    • Displayed documented limits in provider overviews when live quota information is unavailable.
    • Added live API-key quota reporting for additional providers, including OpenRouter, DeepSeek, ClinePass, Z.AI, MiniMax, Moonshot, Venice, Synthetic, DeepInfra, and Neuralwatt.
    • Added localized rate-limit labels in English, German, Japanese, Korean, Russian, and Chinese.
  • Documentation
    • Documented live utilization and reference rate limits in the provider guide.

The providers overview ("Rate limits" section) only showed live
utilization bars for the ~5 providers with quota probes (openai, xai,
anthropic, cursor, kimi, google-antigravity, a6api). Every other
provider — all plain API-key providers, local runtimes, and free tiers —
showed "No rate-limit data yet".

Two-layer fill:

1. Live probes for providers with a real, authenticated usage/balance
   endpoint:
   - openrouter: GET /api/v1/key — renders a credit window against the
     per-key spending cap (skipped when uncapped)
   - deepseek: GET /user/balance — renders a balance window against the
     granted allowance (skipped for top-up-only accounts)
   Both follow the existing probe contract: canonical-host guard,
   redirect: "error", 8s timeout, 4xx(except 408/429) terminal.

2. Documented reference limits for every provider with public rate-limit
   docs: a new `rateLimits` field on the registry entry (rpm/tpm/rpd/
   freeTier/source/updatedAt), threaded through derived presets and the
   /api/providers response to the GUI. Providers populated: groq, google
   (gemini), deepseek, cerebras, deepinfra, sambanova, nebius, together,
   fireworks, openrouter, zai, minimax/minimax-cn, mistral, ollama/vllm/
   lm-studio (local), opencode-free, opencode-zen.

GUI: new ProviderDocumentedLimits renderer shows the reference alongside
the live bars; the dashboard gains a "Documented" section for providers
without a live bar; per-provider overview shows both. New i18n strings
added to all six locales.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Changes

Provider metadata and projection

Layer / File(s) Summary
Registry metadata and API projection
src/providers/registry.ts, src/providers/derive.ts, src/server/management/provider-routes.ts, gui/src/components/provider-catalog/provider-presets.ts, gui/src/provider-workspace/catalog.ts
Adds documented rate-limit metadata and projects it into presets and GET /api/providers responses.
Provider metadata validation
tests/provider-registry-parity.test.ts
Validates metadata provenance, timestamps, non-empty limit information, and Groq preset propagation.

Quota integrations

Layer / File(s) Summary
Provider quota probes
src/providers/quota.ts
Adds canonical-host validation, redirect protection, timeouts, provider-specific parsing, normalized quota windows, and error handling for ten providers.
Quota probe tests
tests/provider-quota.test.ts
Covers authentication, endpoint validation, payload filtering, quota mapping, terminal failures, and transient failures.

Workspace display

Layer / File(s) Summary
Documented limit formatting and rendering
gui/src/components/provider-workspace/ProviderDocumentedLimits.tsx, gui/src/components/provider-workspace/ProviderOverview.tsx
Formats documented limits and renders them with live quota data or as a standalone section.
Dashboard integration, localization, styling, and documentation
gui/src/components/provider-workspace/ProviderOverviewDashboard.tsx, gui/src/i18n/*.ts, gui/src/styles/provider-overview-dashboard.css, docs-site/src/content/docs/guides/providers.md
Lists providers with documented limits that lack live quota rows, adds localized limit strings, styles the section, and documents live versus published limits.
Workspace display tests
gui/tests/provider-capacity.test.ts, gui/tests/provider-capacity-shell.test.tsx
Validates formatting, free-tier text, empty output, and documented-only provider rendering.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ProviderRegistry
  participant ProviderRoutes
  participant ProviderOverviewDashboard
  participant ProviderDocumentedLimits
  ProviderRegistry->>ProviderRoutes: provide rateLimits metadata
  ProviderRoutes-->>ProviderOverviewDashboard: return provider rateLimits
  ProviderOverviewDashboard->>ProviderDocumentedLimits: render documented limits
  ProviderDocumentedLimits-->>ProviderOverviewDashboard: display localized limit summary
Loading

Possibly related PRs

Suggested labels: enhancement

Suggested reviewers: ingwannu, lidge-jun

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: expanding rate-limit coverage in the providers overview.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Follow-up to the rate-limits overview fill: three more providers get
REFRESHING live utilization bars, not just documented reference:

- clinepass: GET /api/v1/users/me/plan/usage-limits — maps the rolling
  five-hour / weekly / monthly ClinePass utilization directly onto the
  existing ProviderQuota windows. A 404 (no active plan) is a no-report,
  not terminal.
- zai: GET /api/monitor/usage/quota/limit — maps the GLM Coding Plan
  5h/weekly/monthly quota windows. Sends the token RAW (no Bearer
  prefix), matching Z.AI's API contract.
- minimax / minimax-cn: GET /v1/token_plan/remains — renders the Token
  Plan remaining-time countdown as a custom window.

All follow the existing probe contract: canonical-host guard before
sending credentials, redirect: "error", 8s timeout, 4xx (except 408/429)
terminal, 5xx/network transient.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/providers/registry.ts`:
- Around line 36-37: Remove English prose from the provider response contracts:
in src/providers/registry.ts lines 36-37, replace freeTier with a localizable
key and parameters or structured limit data; in src/providers/quota.ts line 361,
return an apiCredits kind containing numeric remaining and limit values; in
src/providers/quota.ts line 398, return an apiBalance kind containing numeric
balance and grant values.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 55b822ed-6324-470f-a76b-50f8312dca6c

📥 Commits

Reviewing files that changed from the base of the PR and between b39eecf and 783e4f2.

📒 Files selected for processing (19)
  • gui/src/components/provider-catalog/provider-presets.ts
  • gui/src/components/provider-workspace/ProviderDocumentedLimits.tsx
  • gui/src/components/provider-workspace/ProviderOverview.tsx
  • gui/src/components/provider-workspace/ProviderOverviewDashboard.tsx
  • gui/src/i18n/de.ts
  • gui/src/i18n/en.ts
  • gui/src/i18n/ja.ts
  • gui/src/i18n/ko.ts
  • gui/src/i18n/ru.ts
  • gui/src/i18n/zh.ts
  • gui/src/provider-workspace/catalog.ts
  • gui/tests/provider-capacity-shell.test.tsx
  • gui/tests/provider-capacity.test.ts
  • src/providers/derive.ts
  • src/providers/quota.ts
  • src/providers/registry.ts
  • src/server/management/provider-routes.ts
  • tests/provider-quota.test.ts
  • tests/provider-registry-parity.test.ts

Comment thread src/providers/registry.ts Outdated
Comment on lines +36 to +37
/** Free-tier cap, prose (e.g. "~200 req / 5 hours"). */
freeTier?: string;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Keep user-visible text out of server response contracts.

The registry and quota APIs serialize English prose to the GUI. Locale files cannot translate these values after serialization.

  • src/providers/registry.ts#L36-L37: replace freeTier prose with a localizable key plus parameters, or structured limit data.
  • src/providers/quota.ts#L361-L361: return an apiCredits kind with numeric remaining and limit values instead of an English label.
  • src/providers/quota.ts#L398-L398: return an apiBalance kind with numeric balance and grant values instead of an English label.
📍 Affects 2 files
  • src/providers/registry.ts#L36-L37 (this comment)
  • src/providers/quota.ts#L361-L361
  • src/providers/quota.ts#L398-L398
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/providers/registry.ts` around lines 36 - 37, Remove English prose from
the provider response contracts: in src/providers/registry.ts lines 36-37,
replace freeTier with a localizable key and parameters or structured limit data;
in src/providers/quota.ts line 361, return an apiCredits kind containing numeric
remaining and limit values; in src/providers/quota.ts line 398, return an
apiBalance kind containing numeric balance and grant values.

Source: Path instructions

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 783e4f2b53

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/providers/quota.ts Outdated
Comment on lines +390 to +391
const totalBalance = toFiniteNumber(body?.total_balance);
const grantedBalance = toFiniteNumber(body?.granted_balance);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Read DeepSeek balances from balance_infos

DeepSeek's /user/balance payload places total_balance and granted_balance inside entries of balance_infos, but this reads nonexistent top-level fields, so normal successful responses produce undefined and the new probe returns no report. The regression fixture masks this by duplicating the same values at both levels; select the appropriate currency row from balance_infos instead.

Useful? React with 👍 / 👎.

Comment thread src/providers/quota.ts Outdated
// top-up-only account (granted = 0) has no limit to render utilization.
if (grantedBalance === undefined || grantedBalance <= 0) return null;
if (totalBalance === undefined || totalBalance < 0) return null;
const percent = normalizePercent((totalBalance / grantedBalance) * 100);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Do not report remaining balance as utilization

For a DeepSeek account with grant funds remaining, this ratio increases with the remaining balance, while QuotaBars treats the value as percent used and warns at high percentages. Thus the fixture's $6 of $8 balance is shown as 75% used rather than 25%, and a full balance appears exhausted; moreover, granted_balance is a current balance component rather than the original grant ceiling, so no reliable consumed percentage should be emitted unless an actual ceiling is available.

Useful? React with 👍 / 👎.

discovery: p.liveModels === false ? undefined : getProviderDiscoveryStatus(name),
})));
return jsonResponse(Object.entries(config.providers).map(([name, p]) => {
const registry = getProviderRegistryEntry(name);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Resolve documented limits by provider destination

When a GUI preset is saved under a custom name, such as my-groq with Groq's canonical adapter and base URL, this name-only lookup returns no registry entry and /api/providers omits the documented limits. The dashboard consequently claims that the renamed provider has no rate-limit data; use the existing destination-based registry resolver, as other user-facing provider metadata paths do.

Useful? React with 👍 / 👎.

if (rateLimits.rpm !== undefined) parts.push(t("pws.rateLimits.rpm", { value: formatNumber(rateLimits.rpm) }));
if (rateLimits.tpm !== undefined) parts.push(t("pws.rateLimits.tpm", { value: formatNumber(rateLimits.tpm) }));
if (rateLimits.rpd !== undefined) parts.push(t("pws.rateLimits.rpd", { value: formatNumber(rateLimits.rpd) }));
if (rateLimits.freeTier) parts.push(rateLimits.freeTier);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Translate documented free-tier descriptions

In every non-English locale, this appends the English freeTier prose from the registry verbatim, so rows such as Google and DeepSeek remain partly English despite the surrounding RPM/TPM labels being translated. Model these descriptions as translation keys or structured values and provide them in every locale rather than rendering backend-authored English directly.

AGENTS.md reference: gui/AGENTS.md:L14-L18

Useful? React with 👍 / 👎.

)}
</section>

{documentedLimitProviders.length > 0 && (

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Suppress the empty message when documented limits exist

When there are documented providers but no live quota reports, the live section immediately above still renders pws.dashboard.noRateLimits, and this newly added section then renders the documented data below it. The dashboard therefore simultaneously says “No rate-limit data yet” and displays rate-limit data, contradicting both the feature's fallback behavior and the new regression test; make the empty branch conditional on documentedLimitProviders.length === 0 or change its copy to distinguish live data.

Useful? React with 👍 / 👎.

Comment on lines +35 to +39
<div className="pws-documented-limits">
<span className="pws-documented-limits-label">{t("pws.rateLimits.documented")}</span>
<span className="pws-documented-limits-value">{summary}</span>
{(rateLimits.source || rateLimits.updatedAt) && (
<span className="muted pws-documented-limits-meta">

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Separate and wrap the documented-limit fields

None of the newly introduced pws-documented-limits* classes has a stylesheet rule, and adjacent JSX elements do not introduce text whitespace. Consequently the component renders text such as Documented30 req/min2026-08-06 · https://… with the label, value, and provenance concatenated; the unbroken source URL can also overflow narrow provider rows. Add an explicit layout with gaps and wrapping, or render textual separators.

Useful? React with 👍 / 👎.

Comment thread src/providers/registry.ts Outdated
reasoningSplitModels: MINIMAX_MODELS,
thinkingToggleModels: ["MiniMax-M3"],
jawcodeBundle: "minimax", metadataModelIdNormalize: "case-insensitive", note: "Subscription Key or API Key",
rateLimits: { rpm: 100, tpm: 200_000, freeTier: "Coding plan subscription; per-plan quotas", source: "https://platform.minimax.io/docs/guides/rate-limits", updatedAt: "2026-08-06" },

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Add rate-limit metadata for the MiniMax CN preset

The limits are attached only to minimax, while minimax-cn is a separate registry entry and /api/providers performs an exact registry lookup. A configured MiniMax CN provider therefore remains in the “no data” path even though this change explicitly treats the MiniMax coding-plan variants as covered; add the applicable CN metadata to its canonical registry entry rather than relying on the sibling preset.

AGENTS.md reference: src/AGENTS.md:L18-L18

Useful? React with 👍 / 👎.

return parts.join(" · ");
}

export function ProviderDocumentedLimits({ rateLimits, t }: { rateLimits: DocumentedRateLimits; t: TFn }) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Document the new dashboard rate-limit behavior

This introduces a new user-visible distinction between live utilization and static, tier-dependent documented limits, including provenance and verification dates, but the commit makes no corresponding docs-site/ update. Users need documentation explaining that these figures are references rather than account-specific limits and can drift from their actual tier, as required for dashboard behavior changes.

AGENTS.md reference: gui/AGENTS.md:L36-L36

Useful? React with 👍 / 👎.

Comment thread src/providers/quota.ts Outdated
Comment on lines +354 to +356
const used = usage !== undefined && usage > 0
? usage
: limitRemaining !== undefined ? Math.max(0, limit - limitRemaining) : undefined;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Prefer OpenRouter's authoritative remaining-cap value

For keys with a periodic reset or a spending limit changed after prior usage, usage can represent accumulated spend while limit_remaining represents the current cap window. Preferring usage whenever it is positive therefore makes a reset key appear partly or fully exhausted even when the API reports most of the current limit remaining; derive utilization from limit_remaining when it is present and use usage only as a fallback.

Useful? React with 👍 / 👎.

Comment thread src/providers/quota.ts Outdated
Comment on lines +253 to +255
function isCanonicalDeepSeekBaseUrl(baseUrl: string): boolean {
const normalized = normalizedBaseUrl(baseUrl);
return normalized === DEEPSEEK_BASE_URL;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Accept the supported DeepSeek /v1 base URL

Existing and legacy provider configurations in this repository use https://api.deepseek.com/v1, but this canonical-host check accepts only the equivalent root form. Those valid DeepSeek rows silently skip the new balance probe even though credentials could safely be sent to the fixed root balance endpoint; normalize and accept both canonical path variants, as is already done for A6API.

AGENTS.md reference: src/AGENTS.md:L10-L10

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/providers/quota.ts`:
- Around line 551-558: Update the Token Plan handling near the remainsMs
calculation to avoid assuming a 30-day window: obtain the provider-supplied
total duration before deriving percent, and only calculate/report percentage
when that total is known. When no total duration exists, extend the quota result
to report remainsMs as a duration without a percentage, and add a regression
assertion covering the reported percentage or duration.
- Line 41: Update fetchMinimaxQuota and its caller to select the quota endpoint
by provider region: retain MINIMAX_REMAINS_URL for minimax and use
https://api.minimaxi.com/v1/token_plan/remains for minimax-cn, or disable the CN
probe until that endpoint is explicitly supported. Add coverage verifying the
minimax-cn canonical base URL and ensure both provider paths avoid targeting the
wrong region.

In `@tests/provider-quota.test.ts`:
- Line 691: Remove the duplicate const seen declarations so each test callback
has exactly one declaration: tests/provider-quota.test.ts:691-691 in the
ClinePass test, tests/provider-quota.test.ts:747-747 in the Z.AI test, and
tests/provider-quota.test.ts:800-800 in the MiniMax test. Preserve separate seen
declarations across distinct callback scopes.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: a7981029-105f-4444-9f87-d98f00cdbb66

📥 Commits

Reviewing files that changed from the base of the PR and between 783e4f2 and f01c2ce.

📒 Files selected for processing (2)
  • src/providers/quota.ts
  • tests/provider-quota.test.ts

Comment thread src/providers/quota.ts
Comment thread src/providers/quota.ts
Comment thread tests/provider-quota.test.ts
Following the CodexBar provider reference, five more providers with real
authenticated usage endpoints get REFRESHING live bars (not just documented
reference):

- moonshot: GET /v1/users/me/balance (intl + CN hosts) — account balance
  window from available/voucher/cash.
- venice: GET /api/v1/billing/balance — DIEM balance, or a DIEM epoch
  allocation progress window when present.
- synthetic: GET /v2/quotas — rolling 5-hour / weekly token / search-hourly
  lanes mapped onto the quota windows.
- deepinfra: GET /payment/checklist?compute_owed=true — billing-cycle spend
  against the spending limit, or prepaid balance when no limit is set.
- neuralwatt: GET /v1/quota — subscription kWh usage + prepaid USD credits.

All follow the existing probe contract: canonical-host guard before sending
credentials, redirect: "error", 8s timeout, 4xx (except 408/429) terminal,
5xx/network transient.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/providers/quota.ts`:
- Around line 616-624: Use consumed capacity for quota percentages: in
src/providers/quota.ts lines 616-624, remove the fabricated Moonshot utilization
calculation and emit the established balance-only or zero-utilization fallback;
in src/providers/quota.ts lines 799-803, calculate Neuralwatt utilization as
consumed credits (totalCredits minus remainingCredits) divided by totalCredits.
Update tests/provider-quota.test.ts line 850 to assert the selected Moonshot
balance-only behavior and line 975 to expect 30 percent.

In `@tests/provider-quota.test.ts`:
- Line 846: Add focused regression cases in tests/provider-quota.test.ts at
lines 846-846 and 937-937: extend the Moonshot tests around
fetchProviderQuotaReports and keyQuotaConfig to cover the CN base URL, asserting
a request to https://api.moonshot.cn/v1/users/me/balance; add a DeepInfra
root-base case, asserting a request to
https://api.deepinfra.com/payment/checklist?compute_owed=true.
- Line 836: Remove the duplicate const seen declarations so each test callback
retains exactly one declaration: tests/provider-quota.test.ts lines 836-836 in
the Moonshot test, 874-874 in the Venice test, and 927-927 in the DeepInfra
test. Keep the declarations separate across their distinct test() callback
scopes.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d43c5616-b32c-4437-b69f-d03f1a2362a8

📥 Commits

Reviewing files that changed from the base of the PR and between f01c2ce and fa659ca.

📒 Files selected for processing (2)
  • src/providers/quota.ts
  • tests/provider-quota.test.ts

Comment thread src/providers/quota.ts Outdated
Comment thread tests/provider-quota.test.ts
Comment thread tests/provider-quota.test.ts
…nd UI

Codex connector findings:

- DeepSeek: read total/granted from `balance_infos` rows (currency-selected)
  instead of nonexistent top-level fields; report a balance-only window
  (granted_balance is a current component, not a grant ceiling — no
  fabricated utilization). Accept the canonical `/v1` base URL.
- OpenRouter: derive utilization from `limit_remaining` (authoritative for
  reset/re-capped keys) and treat a successful no-cap response as TERMINAL
  so an old capped bar is dropped instead of preserved as last-good.
- Moonshot: report balance-only (percent 0) — no fabricated utilization.
- Neuralwatt: report CONSUMED credits (total - remaining)/total, not the
  remaining share.
- MiniMax: select the CN `token_plan/remains` host for minimax-cn; never
  assume a 30-day window — report a duration-only window unless the API
  supplies a plan total.
- provider-routes: resolve documented limits by provider DESTINATION
  (registryEntryForProviderDestination) so a preset saved under a custom
  name still shows its limits.
- registry: add rateLimits to the minimax-cn entry (exact lookup).
- GUI: nest documented rows inside the rate-limits column (preserves the
  2-col dashboard grid); suppress "No rate-limit data yet" when documented
  limits exist; add documented-limits CSS (gaps, wrapping, overflow).
- i18n: localize free-tier prose via translation keys in all six locales
  instead of rendering backend-authored English verbatim.
- docs-site: document the live-vs-documented rate-limit distinction.

CodeRabbit findings:

- MiniMax: no presumed 30-day window; regression coverage for the
  duration-only and consumed-share paths, and the CN host.
- Tests: update assertions for the behavior changes (deepseek balance-only,
  moonshot balance-only, neuralwatt consumed, minimax duration-only) and add
  regression cases (moonshot CN, deepinfra root base, deepseek /v1,
  openrouter reset-key + cap-removal).

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@gui/src/components/provider-workspace/ProviderDocumentedLimits.tsx`:
- Around line 28-46: Update FREE_TIER_KEYS to type its values as
Parameters<TFn>[0] so mapped translation keys remain validated against TFn’s
accepted key type, then change localizeFreeTier to call t(key) directly without
the never cast.

In `@src/providers/quota.ts`:
- Around line 597-610: Update the MiniMax quota handling around the totalMs
fallback so an unknown plan duration never reports percent: 0; extend the quota
result contract to carry the remaining duration with an optional percentage, or
suppress the row until totalMs is available. Update the existing provider quota
regression test near the MiniMax cases to assert the percentage is absent when
the API omits the total duration.
- Around line 402-405: Update the quota calculation around used so usage is
accepted when it is finite and equal to zero, while still treating absent or
invalid usage as unavailable when limitRemaining is undefined. Preserve the
existing limitRemaining precedence and null behavior otherwise, and add a
regression case for an OpenRouter response with limit 20 and usage 0 that
reports zero consumption and $20 remaining.

In `@tests/provider-quota.test.ts`:
- Around line 641-643: In the “DeepSeek quota renders a balance-only window from
balance_infos” test callback, remove the duplicate seen declarations and retain
a single const seen variable for the fetch mock and assertions so the
provider-quota test file parses successfully.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 556c8d7b-0c8d-43cc-abd5-d586255035e1

📥 Commits

Reviewing files that changed from the base of the PR and between fa659ca and 118ba32.

📒 Files selected for processing (14)
  • docs-site/src/content/docs/guides/providers.md
  • gui/src/components/provider-workspace/ProviderDocumentedLimits.tsx
  • gui/src/components/provider-workspace/ProviderOverviewDashboard.tsx
  • gui/src/i18n/de.ts
  • gui/src/i18n/en.ts
  • gui/src/i18n/ja.ts
  • gui/src/i18n/ko.ts
  • gui/src/i18n/ru.ts
  • gui/src/i18n/zh.ts
  • gui/src/styles/provider-overview-dashboard.css
  • src/providers/quota.ts
  • src/providers/registry.ts
  • src/server/management/provider-routes.ts
  • tests/provider-quota.test.ts

Comment thread gui/src/components/provider-workspace/ProviderDocumentedLimits.tsx Outdated
Comment thread src/providers/quota.ts
Comment thread src/providers/quota.ts Outdated
Comment thread tests/provider-quota.test.ts
Three valid findings from the latest review round:

- GUI: type FREE_TIER_KEYS values as `Parameters<TFn>[0]` so mapped
  translation keys stay validated against TFn's TKey constraint, and call
  `t(key)` directly without the `never` cast.
- OpenRouter: accept `usage: 0` (a capped key with zero consumption must
  render 0% used / full cap remaining); `usage >= 0` replaces `usage > 0`.
- MiniMax: when the API omits the plan total duration, suppress the row
  instead of reporting `percent: 0` — a 0% bar would falsely claim zero
  consumption. Only render a consumed share when a provider-supplied total
  is known.

The remaining reported items (duplicate `const seen` in tests, and several
"Addressed in commit 118ba32" markers) were verified against the current
tree: each `seen` declaration lives in its own test callback scope and the
suite parses and passes (84 quota tests green), so those findings are stale.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@gui/src/components/provider-workspace/ProviderDocumentedLimits.tsx`:
- Around line 44-46: The localizeFreeTier function must not return unmapped
freeTier text directly. Add locale entries and FREE_TIER_KEYS mappings for every
provider-owned description, and use an existing localized fallback for unknown
values; then add a regression test covering an unmapped value without hardcoding
user-visible text in gui code.

In `@src/providers/quota.ts`:
- Around line 601-602: The MiniMax quota path incorrectly treats a successful
response without total duration as transient, preserving stale utilization. In
src/providers/quota.ts lines 601-602, update the handling around totalMs in
fetchProviderQuotaReports to return the established cache-clearing sentinel,
matching the OpenRouter no-cap path. Add the focused regression test in
tests/provider-quota.test.ts lines 856-869: cache a valid total-duration row,
force-refresh with no total duration, and assert reports is empty.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 4aec6368-ea32-4dad-baba-ec39a30a29bf

📥 Commits

Reviewing files that changed from the base of the PR and between 118ba32 and dd7c7ce.

📒 Files selected for processing (3)
  • gui/src/components/provider-workspace/ProviderDocumentedLimits.tsx
  • src/providers/quota.ts
  • tests/provider-quota.test.ts

Comment thread gui/src/components/provider-workspace/ProviderDocumentedLimits.tsx Outdated
Comment thread src/providers/quota.ts Outdated
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

✅ READY

  • all PR quality gates passed.

@github-actions
github-actions Bot marked this pull request as draft August 6, 2026 22:53
@github-actions github-actions Bot added the enhancement New feature or request label Aug 6, 2026
@Wibias

Wibias commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator Author

not gui

@github-actions
github-actions Bot marked this pull request as ready for review August 6, 2026 23:02
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Deterministic PR hygiene checks passed.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dd7c7ce374

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +249 to +250
const registry = getProviderRegistryEntry(name)
?? registryEntryForProviderDestination(p);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Match documented limits to the actual provider destination

For a configured key provider whose name collides with a registry id but whose transport was edited, e.g. groq pointing at https://custom.example/v1, this exact-id lookup wins before the destination resolver and /api/providers still returns Groq's documented limits for an unrelated upstream. Fresh evidence: the current resolver still chooses getProviderRegistryEntry(name) before checking the provider's adapter/baseUrl, so the dashboard can display authoritative-looking limits for the wrong vendor; gate the exact lookup with a transport match or prefer the destination resolver for key-auth rows.

Useful? React with 👍 / 👎.

Comment thread src/providers/quota.ts
* weekly token, search-hourly) mapped onto the quota windows.
*/
async function fetchSyntheticQuota(provider: string, config: OcxProviderConfig): Promise<ProviderQuotaProbeResult> {
if (!isCanonicalSyntheticBaseUrl(config.baseUrl)) return null;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Accept the Synthetic preset URL for quota probing

The built-in Synthetic preset still routes traffic through https://api.synthetic.new/openai/v1, but this new quota probe only accepts https://api.synthetic.new/v2 before fetching /quotas. A normal Synthetic provider added from the catalog therefore never reaches the live quota endpoint and silently falls back to no live row, despite the docs listing Synthetic as probed; derive/allow the quota host alongside the registry transport instead of hardcoding a conflicting canonical base URL.

Useful? React with 👍 / 👎.

disabled: p.disabled === true,
codexAccountMode: providerCodexAccountMode(name, p),
discovery: p.liveModels === false ? undefined : getProviderDiscoveryStatus(name),
...(registry?.rateLimits ? { rateLimits: { ...registry.rateLimits } } : {}),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Put documented limits on the config DTO

The Providers workspace never consumes this /api/providers list for its provider map: useProvidersFetch.fetchConfig() loads /api/config and passes config.providers into ProviderWorkspaceShell. Because safeConfigDTO() still omits rateLimits, the new documented-limit UI receives no data in normal use (the regression test only injects the field manually), so the documented rows do not render; add the resolved metadata to the /api/config DTO or switch the workspace to the enriched provider list.

Useful? React with 👍 / 👎.

Comment thread src/providers/quota.ts Outdated
const apiKey = resolveEnvValue(config.apiKey)?.trim();
if (!apiKey) return null;
const response = await fetch(`${ZAI_BASE_URL}/api/monitor/usage/quota/limit`, {
headers: { Accept: "application/json", Authorization: apiKey },

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Send the Z.AI quota key as a bearer token

For standard Z.AI Coding Plan keys, this sends the raw key as the entire Authorization value, while Z.AI's own API reference requires HTTP Bearer authentication (Authorization: Bearer ZAI_API_KEY) and the existing OpenAI-chat adapter sends Z.AI model calls that way. The quota probe will therefore get 401/auth-missing for the same key that successfully serves completions; prefix the key with Bearer here as well.

Useful? React with 👍 / 👎.

Comment thread src/providers/quota.ts Outdated
// total there is no percentage to render, so suppress the row rather than
// report a false 0% (zero would mean "no consumption").
const totalMs = toFiniteNumber(data.total_time ?? data.plan_duration_ms ?? data.total_duration_ms);
if (totalMs === undefined || totalMs <= 0) return null;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Drop stale MiniMax rows when no total is available

When MiniMax returns a valid remains payload without total_time after a previous refresh did include it, this null is treated as a transient probe failure by the aggregator and preserves the old utilization row for up to 30 minutes. The comment says this case should suppress the row rather than fabricate utilization, so return the terminal/no-row result instead of the transient one.

Useful? React with 👍 / 👎.

Comment thread src/providers/quota.ts
Comment on lines +721 to +722
const fiveHour = percentAt("rollingFiveHourLimit");
const weekly = percentAt("weeklyTokenLimit");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Parse Synthetic's documented subscription quota shape

Even after the Synthetic probe reaches /v2/quotas, the current documented response shape is subscription: { limit, requests, renewsAt }, not rollingFiveHourLimit or weeklyTokenLimit. A normal successful response from the official endpoint therefore produces no windows and no live row; map subscription.requests / subscription.limit (and renewsAt) before falling back to the older field names.

Useful? React with 👍 / 👎.

Comment thread src/providers/quota.ts
if (!response.ok) {
// 404 = no active plan; a plain "no plan" is a no-report, everything else
// 4xx (except 408/429) is a credential/contract problem.
if (response.status === 404) return null;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Treat Cline's no-plan response as clearing the row

If a ClinePass account previously returned usage limits and a later refresh returns the documented 404/no-active-plan response, this null makes the aggregator preserve the old bars as a transient failure for up to 30 minutes. Since this branch explicitly classifies 404 as a real no-report state, it should suppress any previous row rather than leave stale plan usage visible.

Useful? React with 👍 / 👎.

Wibias and others added 5 commits August 7, 2026 01:21
Five findings from the latest Codex review:

- provider-routes + config DTO: documented limits now resolve purely by
  DESTINATION for key providers (a renamed preset like "my-groq" keeps
  Groq's limits; a key provider whose transport was edited to a custom
  host does NOT inherit the registry id's limits). Forward/oauth/local
  presets resolve by id, matching the note-resolution pattern.
- config DTO (/api/config): safeConfigDTO now carries rateLimits so the
  Providers workspace (which loads /api/config, not /api/providers) gets
  the documented limits; the GUI ProvidersConfig type gained the field.
- Z.AI: send the key as a Bearer token (Authorization: Bearer <key>) per
  the Z.AI API reference, not the raw key.
- MiniMax: a valid response that omits the plan total after a prior
  refresh had it is a DELIBERATE contract change — return TERMINAL so the
  stale row is dropped instead of preserved as a transient last-good.
- Synthetic: accept the preset base URL (api.synthetic.new/openai/v1) in
  addition to /v2 for the quota probe.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
Two dev/runtime fixes for the Providers rate-limits UI:

- Upgrade @vitejs/plugin-react 6.0.3 -> 6.0.5. The 6.0.3 release failed to
  inject the fast-refresh preamble in dev on Vite 8, so every component
  module threw `Uncaught ReferenceError: $RefreshReg$ is not defined` and
  the dashboard would not boot under `bun run dev`.

- Split ProviderDocumentedLimits.tsx into a component-only module plus a
  pure provider-workspace/documented-limits.ts (types, FREE_TIER_KEYS,
  formatDocumentedLimits). The component file previously exported
  non-component helpers, which violates react-refresh/only-export-components
  and breaks fast refresh; the lint gate flagged it.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
Command Code (commandcode) gets a live utilization probe using the API key
already stored by `ocx login command-code`:

- GET https://api.commandcode.ai/internal/billing/credits — rolling
  5-hour and weekly utilization windows plus monthly credit balances
- GET https://api.commandcode.ai/internal/billing/subscriptions — the
  active plan, whose grant total produces the monthly consumed-share bar

Maps onto the ProviderQuota windows (fiveHourPercent/weeklyPercent/
monthlyPercent) and follows the existing probe contract: canonical-host
guard before sending the credential, redirect: "error", 8s timeout, 4xx
(except 408/429) terminal, 5xx/network transient.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
Drop the "Documented" reference-limits feature entirely — it was bloat.
The providers overview now shows only LIVE utilization bars from probed
usage endpoints.

Removed:
- ProviderRateLimits type + rateLimits data on all registry entries
- rateLimits plumbing through derived presets, safeConfigDTO, and
  /api/providers
- the ProviderDocumentedLimits component + documented-limits.ts pure
  module, the dashboard "Documented" section, catalog/preset/config DTO
  rateLimits fields, and all pws.rateLimits.* i18n keys (en + 5 locales)
- the documented-limits CSS and the related tests (registry parity,
  config DTO, GUI capacity + shell)

Docs updated to describe only the live utilization probes.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
… API)

The Command Code billing endpoints (/internal/billing/credits,
/internal/billing/subscriptions) require the browser better-auth session
cookie — the API key opencodex stores via `ocx login command-code` is
rejected with 401 "You're logged out" (only /alpha/whoami accepts the
key). There is no API-key-accessible quota endpoint, so the probe could
never produce a report.

Remove the probe, its dispatcher branch, constants, and tests rather
than ship dead code that claims a live meter.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
@Wibias
Wibias merged commit b401f39 into lidge-jun:dev Aug 7, 2026
21 checks passed
@Wibias
Wibias deleted the feat/provider-rate-limits branch August 7, 2026 00:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant