Repository navigation
feat(billing): drop rate-limit UI, surface cycle usage insights - #2027
Conversation
Backend PR tinyhumansai/backend#790 disabled 5-hour and daily-cap rate-limit enforcement and reshaped GET /teams/me/usage. The cap fields (cycleLimit5hr, fiveHourCapUsd, fiveHourResetsAt, bypassCycleLimit, cycleLimit7day) are gone; the response now exposes cycleSpentUsd, a plan{} block (margin + discountVsPayAsYouGoPercent), and an insights{} block (per-day spend series, top-10 models, top-10 integrations, inference-vs-integrations totals). Frontend changes: - TeamUsage type + normalizer rebuilt for the new shape. - useUsageState: dropped isRateLimited / usagePct10h; usagePct now derives from the cycle budget alone. - Removed UsageLimitModal entirely (no more 5-hour countdown modal) and the composer block-feedback's showLimitModal flag. - Conversations: dropped 5h LimitPill, rate-limit banner branch, modal mount. The cycle pill + tooltip now shows cycleSpentUsd / budget / remaining only. - AIPanel ledger: replaced "5h window" tile with "Cycle total spend" (inference + integration breakdown) and pointed "Week remaining" detail at cycleSpentUsd. - InferenceBudget panel rebuilt with cycle-spend breakdown, daily inference/integrations chart, top models, top integrations, and a plan-discount badge driven by plan.discountVsPayAsYouGoPercent. - PLANS: removed fiveHourCapUsd, refocused features on per-call discount (BASIC 50%, PRO 90%) per the new backend pricing story. - Home: dropped isRateLimited banner branch. - TokenUsagePill / GlobalUpsellBanner: use the unified usagePct. - i18n (en/zh-CN/id): dropped chat.rateLimitReached, chat.fiveHourLimit, chat.weeklyLimit; added chat.cycle / cycleSpent / cycleRemaining and retuned chat.weeklyLimitHit copy. - Types: dropped fiveHourCapUsd from CurrentPlanData. Tests updated for the new shape (creditsApi, useUsageState, AIPanel, Conversations.render, billingApi, billingHelpers, Home, composerSendDecision). 2500 passing. The Rust team_get_usage handler is a passthrough so no core-side changes are required — the new JSON flows through unchanged.
|
Note Reviews pausedIt 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 Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughRefactors quota handling from short-term rate limits to a unified cycle-budget model: API types/normalizers now expose cycleSpent and insights, useUsageState exposes a single usagePct, billing UI shows cycle spend and charts, modal-based limit flow removed, and pages/tests/i18n updated. ChangesCycle-Based Usage Budget Refactor
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (3)
app/src/hooks/useUsageState.test.ts (1)
87-207: ⚡ Quick winAdd a regression case for over-remaining budgets.
Please add one case where
remainingUsd > cycleBudgetUsdand assertusagePct === 0plusisNearLimit === falseto lock the lower-bound behavior.🤖 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 `@app/src/hooks/useUsageState.test.ts` around lines 87 - 207, Add a test in useUsageState.test.ts that simulates an over-remaining budget by importing useUsageState, stubbing mockGetCurrentPlan (e.g. basicPlan()) and mockGetTeamUsage to return buildUsage({ remainingUsd: 15, cycleBudgetUsd: 10 }), render the hook, wait for isLoading to be false, and assert that result.current.usagePct === 0 and result.current.isNearLimit === false (optionally also assert isBudgetExhausted === false) to lock the lower-bound behavior for over-remaining budgets.app/src/pages/__tests__/Conversations.render.test.tsx (1)
618-627: ⚡ Quick winAssert inline error feedback in the over-budget send test.
This test correctly verifies
chatSendsuppression, but it should also assert the inline budget-exhausted message to lock in the modal-removal UX behavior.Suggested test assertion update
it('blocks the send when the account is over budget (no rate-limit modal anymore)', async () => { const { textarea } = await renderSelectedConversation({ isAtLimit: true }); await submitComposerText(textarea, 'hello at limit'); // Backend PR `#790` removed the rate-limit modal; over-budget now surfaces // only the inline send-error (which clears as soon as the user keeps // typing). The contract we still care about: chatSend is suppressed. expect(chatSend).not.toHaveBeenCalled(); + expect(screen.getByText(/Included budget exhausted/i)).toBeInTheDocument(); });As per coding guidelines: "Prefer testing behavior over implementation details."
🤖 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 `@app/src/pages/__tests__/Conversations.render.test.tsx` around lines 618 - 627, Update the test "blocks the send when the account is over budget (no rate-limit modal anymore)" to also assert the inline budget-exhausted feedback is shown: after calling renderSelectedConversation({ isAtLimit: true }) and submitComposerText(textarea, 'hello at limit'), keep the existing expect(chatSend).not.toHaveBeenCalled() and add an assertion that the inline error message element or text for the budget-exhausted state is present (use the same query utilities used elsewhere in the file to find the inline send-error). Locate this test by the it(...) description and use renderSelectedConversation, submitComposerText, and textarea to place the new assertion so the test verifies both suppression of chatSend and the inline error UX.app/src/components/settings/panels/AIPanel.tsx (1)
900-1339: 🏗️ Heavy liftExtract the diagnostics/ledger section into separate modules.
This file has grown far beyond single-responsibility size, and the added budget diagnostics increase coupling and review/test overhead.
As per coding guidelines
**/*.{js,ts,tsx,jsx}: Prefer files ≤ ~500 lines per source file; split modules when growing to maintain readability and single responsibility.🤖 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 `@app/src/components/settings/panels/AIPanel.tsx` around lines 900 - 1339, The AIPanel.tsx file is too large—extract the recent usage ledger and budget/loop diagnostic sections into separate components to reduce size and coupling: create e.g. LedgerPanel, BudgetMathPanel, and LoopCallBudgetPanel (or a single DiagnosticsLedger component) that encapsulate the JSX around MetricTile, FormulaRow, the "Latest spend" block, "Top actions" and "Top hours" lists and the surrounding state usage (props: usage, spendSample, spendRows, latestSpend, actionSummary, hourSummary, backgroundApiReadsPerWeek, calendarPlannerCallsPerWeek, etc.), export them and replace the in-file sections with imports and a single component invocation passing the necessary props (preserve handlers like refresh/runPlannerNow only if used); ensure all referenced symbols (MetricTile, FormulaRow, spendAmount, formatUsd, formatCount, COMPOSIO_PERIODIC_TICK_MINUTES, MEMORY_WORKERS, MEMORY_POLL_SECONDS) remain available via imports or prop drilling and update tests/imports accordingly.
🤖 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 `@app/src/components/settings/panels/billing/InferenceBudget.tsx`:
- Around line 43-46: The progress bar width calculation in InferenceBudget.tsx
uses (teamUsage.remainingUsd / teamUsage.cycleBudgetUsd) * 100 which can produce
negative or >100 values; fix by computing the percent from
teamUsage.remainingUsd and teamUsage.cycleBudgetUsd, guard against
division-by-zero, then clamp that percent into the 0–100 range (e.g. with
Math.max/Math.min) before interpolating into the width style so the style.width
always yields a valid percentage.
- Line 55: The "Cycle ends" line should validate and consistently format
teamUsage.cycleEndsAt to avoid "Invalid Date" or local-time shifts for
UTC-midnight values: in the InferenceBudget component, check
Date.parse(teamUsage.cycleEndsAt) (or new Date(...) validity) and if invalid
render a safe placeholder (e.g. "—" or "Invalid date"); otherwise create a Date
object and format with toLocaleDateString('en-US', { timeZone: 'UTC' }) (or an
explicit timezone option) when rendering the "Cycle ends {…}" text so
UTC-midnight timestamps don't shift to the previous/next day in the user's local
timezone.
In `@app/src/hooks/useUsageState.ts`:
- Around line 111-114: The computed usagePct in useUsageState.ts can be negative
when teamUsage.remainingUsd > teamUsage.cycleBudgetUsd; update the calculation
for the usagePct variable to clamp the value to the [0,1] range by applying
Math.max(0, ...) around the current fraction (and keep Math.min(1, ...)) so
usagePct never becomes negative while still respecting the upper bound; locate
the usagePct declaration that references teamUsage.cycleBudgetUsd and
teamUsage.remainingUsd and replace the expression accordingly.
---
Nitpick comments:
In `@app/src/components/settings/panels/AIPanel.tsx`:
- Around line 900-1339: The AIPanel.tsx file is too large—extract the recent
usage ledger and budget/loop diagnostic sections into separate components to
reduce size and coupling: create e.g. LedgerPanel, BudgetMathPanel, and
LoopCallBudgetPanel (or a single DiagnosticsLedger component) that encapsulate
the JSX around MetricTile, FormulaRow, the "Latest spend" block, "Top actions"
and "Top hours" lists and the surrounding state usage (props: usage,
spendSample, spendRows, latestSpend, actionSummary, hourSummary,
backgroundApiReadsPerWeek, calendarPlannerCallsPerWeek, etc.), export them and
replace the in-file sections with imports and a single component invocation
passing the necessary props (preserve handlers like refresh/runPlannerNow only
if used); ensure all referenced symbols (MetricTile, FormulaRow, spendAmount,
formatUsd, formatCount, COMPOSIO_PERIODIC_TICK_MINUTES, MEMORY_WORKERS,
MEMORY_POLL_SECONDS) remain available via imports or prop drilling and update
tests/imports accordingly.
In `@app/src/hooks/useUsageState.test.ts`:
- Around line 87-207: Add a test in useUsageState.test.ts that simulates an
over-remaining budget by importing useUsageState, stubbing mockGetCurrentPlan
(e.g. basicPlan()) and mockGetTeamUsage to return buildUsage({ remainingUsd: 15,
cycleBudgetUsd: 10 }), render the hook, wait for isLoading to be false, and
assert that result.current.usagePct === 0 and result.current.isNearLimit ===
false (optionally also assert isBudgetExhausted === false) to lock the
lower-bound behavior for over-remaining budgets.
In `@app/src/pages/__tests__/Conversations.render.test.tsx`:
- Around line 618-627: Update the test "blocks the send when the account is over
budget (no rate-limit modal anymore)" to also assert the inline budget-exhausted
feedback is shown: after calling renderSelectedConversation({ isAtLimit: true })
and submitComposerText(textarea, 'hello at limit'), keep the existing
expect(chatSend).not.toHaveBeenCalled() and add an assertion that the inline
error message element or text for the budget-exhausted state is present (use the
same query utilities used elsewhere in the file to find the inline send-error).
Locate this test by the it(...) description and use renderSelectedConversation,
submitComposerText, and textarea to place the new assertion so the test verifies
both suppression of chatSend and the inline error UX.
🪄 Autofix (Beta)
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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 3936170a-dd39-49c0-8bfb-13742018bf65
📒 Files selected for processing (23)
app/src/components/chat/TokenUsagePill.tsxapp/src/components/settings/panels/AIPanel.tsxapp/src/components/settings/panels/__tests__/AIPanel.test.tsxapp/src/components/settings/panels/__tests__/billingHelpers.test.tsapp/src/components/settings/panels/billing/InferenceBudget.tsxapp/src/components/settings/panels/billingHelpers.tsapp/src/components/upsell/GlobalUpsellBanner.tsxapp/src/components/upsell/UsageLimitModal.tsxapp/src/hooks/useUsageState.test.tsapp/src/hooks/useUsageState.tsapp/src/lib/i18n/en.tsapp/src/lib/i18n/id.tsapp/src/lib/i18n/zh-CN.tsapp/src/pages/Conversations.tsxapp/src/pages/Home.tsxapp/src/pages/__tests__/Conversations.render.test.tsxapp/src/pages/__tests__/Home.test.tsxapp/src/pages/conversations/composerSendDecision.test.tsapp/src/pages/conversations/composerSendDecision.tsapp/src/services/api/__tests__/billingApi.test.tsapp/src/services/api/__tests__/creditsApi.test.tsapp/src/services/api/creditsApi.tsapp/src/types/api.ts
💤 Files with no reviewable changes (3)
- app/src/components/upsell/UsageLimitModal.tsx
- app/src/types/api.ts
- app/src/services/api/tests/billingApi.test.ts
Address CodeRabbit review on PR tinyhumansai#2027: - useUsageState: clamp usagePct to [0,1] so an overage (remainingUsd > cycleBudgetUsd) can't leak a negative ratio into the chat pill and near-limit derivations. - InferenceBudget: clamp progress-bar width to [0,100] for the same reason, and route the cycle-end label through a formatter that validates the timestamp and renders in UTC so a UTC-midnight cycle end doesn't shift a day in the user's local TZ.
…ts-show-usage # Conflicts: # app/src/components/settings/panels/billing/InferenceBudget.tsx # app/src/components/upsell/GlobalUpsellBanner.tsx # app/src/components/upsell/UsageLimitModal.tsx # app/src/lib/i18n/id.ts # app/src/lib/i18n/zh-CN.ts
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (8)
app/src/lib/i18n/chunks/fr-2.ts (1)
289-297:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winReplace weekly-limit phrasing with cycle-budget phrasing.
Line 289 is still weekly-limit copy, while Lines 295-297 are cycle-based labels. Please align
chat.weeklyLimitHitwith the cycle-budget terminology.🤖 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 `@app/src/lib/i18n/chunks/fr-2.ts` around lines 289 - 297, Update the French translation for the key chat.weeklyLimitHit to use cycle-budget terminology instead of weekly wording; locate the chat.weeklyLimitHit entry and replace "Tu as atteint ta limite hebdomadaire." with a cycle-consistent phrase such as "Tu as atteint ton budget pour ce cycle." to align with the surrounding keys (chat.cycle, chat.cycleSpent, chat.cycleRemaining).app/src/lib/i18n/chunks/bn-2.ts (1)
284-292:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winUpdate weekly-limit copy to cycle-budget copy in this locale.
Line 284 still references a weekly limit while Lines 290-292 moved to cycle wording. Please align
chat.weeklyLimitHitwith the cycle-budget model.🤖 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 `@app/src/lib/i18n/chunks/bn-2.ts` around lines 284 - 292, Update the 'chat.weeklyLimitHit' translation to use the cycle-budget wording (to match 'chat.cycle', 'chat.cycleSpent', and 'chat.cycleRemaining') by replacing the current weekly-limit text with a cycle-budget message — e.g., change the value for chat.weeklyLimitHit to something like "আপনি আপনার চক্রের বাজেটে পৌঁছেছেন।" so all budget-related keys consistently use "চক্র" (cycle) terminology.app/src/lib/i18n/chunks/es-2.ts (1)
287-295:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winKeep
chat.weeklyLimitHitconsistent with cycle-based UX.Line 287 still says weekly limit, but Lines 293-295 use cycle terminology. Please update the weekly-limit string to cycle-budget wording.
🤖 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 `@app/src/lib/i18n/chunks/es-2.ts` around lines 287 - 295, The key 'chat.weeklyLimitHit' uses "weekly" while surrounding keys ('chat.cycle', 'chat.cycleSpent', 'chat.cycleRemaining', 'chat.budgetComplete') use cycle/budget terminology—update the value for 'chat.weeklyLimitHit' to match cycle-based UX (e.g., change the string to mention "presupuesto de ciclo" or "ciclo" instead of "semanal") so it is consistent with the other cycle-related keys.app/src/lib/i18n/chunks/ru-2.ts (1)
282-290:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winMake
chat.weeklyLimitHitconsistent with cycle-budget copy.Line 282 still says weekly-limit messaging, which conflicts with cycle labels on Lines 288-290. Please localize this message to the cycle-budget concept.
🤖 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 `@app/src/lib/i18n/chunks/ru-2.ts` around lines 282 - 290, The message for 'chat.weeklyLimitHit' is inconsistent with the cycle-budget terminology used by 'chat.cycle', 'chat.cycleSpent', and 'chat.cycleRemaining'; update the localization for the 'chat.weeklyLimitHit' entry to mention the cycle-based limit (e.g., replace any "weekly" wording with "cycle" or equivalent Russian phrasing) so it matches the cycle-budget copy used elsewhere in this file.app/src/lib/i18n/chunks/ar-2.ts (1)
274-281:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winAlign
chat.weeklyLimitHittext with cycle-budget terminology.Line 274 still communicates a weekly limit, which conflicts with the new cycle labels on Lines 279-281. Please update this locale string to the cycle-budget concept.
🤖 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 `@app/src/lib/i18n/chunks/ar-2.ts` around lines 274 - 281, Update the locale entry for chat.weeklyLimitHit to use cycle-budget terminology: replace the current Arabic text "لقد وصلت إلى حدك الأسبوعي." with a cycle-focused phrase such as "لقد وصلت إلى حدك في هذه الدورة." to match keys like chat.cycle, chat.cycleSpent and chat.cycleRemaining; modify the value for the 'chat.weeklyLimitHit' key accordingly.app/src/lib/i18n/chunks/hi-2.ts (1)
282-289:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winAlign
chat.weeklyLimitHitwith cycle-budget messaging.Line 282 still refers to a weekly limit, which conflicts with the cycle labels on Lines 287-289. Please update the string to cycle-budget wording.
🤖 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 `@app/src/lib/i18n/chunks/hi-2.ts` around lines 282 - 289, Update the 'chat.weeklyLimitHit' translation to use cycle-budget terminology so it aligns with the surrounding keys ('chat.cycle', 'chat.cycleSpent', 'chat.cycleRemaining'); locate the 'chat.weeklyLimitHit' entry in hi-2.ts and replace the "साप्ताहिक सीमा" wording with a phrase that references the cycle/budget (consistent tone with 'chat.budgetComplete' and 'chat.cycle'), ensuring the key remains unchanged.app/src/lib/i18n/chunks/pt-2.ts (1)
287-295:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winUpdate weekly-limit string to the cycle-budget model.
Line 287 still communicates a weekly limit, while Lines 293-295 moved to cycle semantics. Please align
chat.weeklyLimitHitaccordingly.🤖 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 `@app/src/lib/i18n/chunks/pt-2.ts` around lines 287 - 295, Update the 'chat.weeklyLimitHit' translation to use cycle-budget wording to match the rest of the keys (e.g., chat.cycle, chat.cycleSpent, chat.cycleRemaining, chat.budgetComplete); replace the weekly-specific phrase ("Você atingiu seu limite semanal.") with a Portuguese message that communicates the cycle budget has been reached (e.g., using "ciclo" or "orçamento do ciclo") so all cycle-related strings are consistent.app/src/lib/i18n/chunks/zh-CN-2.ts (1)
265-265:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winUpdate non-English translations to match cycle-based messaging.
The
chat.weeklyLimitHitkey is actively used inapp/src/pages/Conversations.tsx:1855for quota exhaustion messages. However, there's a localization inconsistency: the English versions (en-2.tsanden.ts) say"You've used your included cycle budget."(cycle-based), while the Chinese and most other locales still say "weekly limit" (time-window-based).Update the following locale files to use cycle terminology instead of weekly:
zh-CN-2.tsline 265: change'已达到每周限制。'to'已使用包含的循环预算。'fr-2.ts,es-2.ts,pt-2.ts,ru-2.ts,ar-2.ts,hi-2.ts,id-2.ts,bn-2.ts: align translations to match the English cycle-based message🤖 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 `@app/src/lib/i18n/chunks/zh-CN-2.ts` at line 265, Update the localization key 'chat.weeklyLimitHit' to use cycle-based wording instead of "weekly" for the listed locales; specifically in zh-CN-2.ts replace '已达到每周限制。' with '已使用包含的循环预算。' and apply equivalent cycle-based translations in fr-2.ts, es-2.ts, pt-2.ts, ru-2.ts, ar-2.ts, hi-2.ts, id-2.ts, and bn-2.ts so they match the English message "You've used your included cycle budget." Ensure the exact key 'chat.weeklyLimitHit' is updated in each file and keep punctuation/period consistent with other locale entries.
🤖 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.
Outside diff comments:
In `@app/src/lib/i18n/chunks/ar-2.ts`:
- Around line 274-281: Update the locale entry for chat.weeklyLimitHit to use
cycle-budget terminology: replace the current Arabic text "لقد وصلت إلى حدك
الأسبوعي." with a cycle-focused phrase such as "لقد وصلت إلى حدك في هذه الدورة."
to match keys like chat.cycle, chat.cycleSpent and chat.cycleRemaining; modify
the value for the 'chat.weeklyLimitHit' key accordingly.
In `@app/src/lib/i18n/chunks/bn-2.ts`:
- Around line 284-292: Update the 'chat.weeklyLimitHit' translation to use the
cycle-budget wording (to match 'chat.cycle', 'chat.cycleSpent', and
'chat.cycleRemaining') by replacing the current weekly-limit text with a
cycle-budget message — e.g., change the value for chat.weeklyLimitHit to
something like "আপনি আপনার চক্রের বাজেটে পৌঁছেছেন।" so all budget-related keys
consistently use "চক্র" (cycle) terminology.
In `@app/src/lib/i18n/chunks/es-2.ts`:
- Around line 287-295: The key 'chat.weeklyLimitHit' uses "weekly" while
surrounding keys ('chat.cycle', 'chat.cycleSpent', 'chat.cycleRemaining',
'chat.budgetComplete') use cycle/budget terminology—update the value for
'chat.weeklyLimitHit' to match cycle-based UX (e.g., change the string to
mention "presupuesto de ciclo" or "ciclo" instead of "semanal") so it is
consistent with the other cycle-related keys.
In `@app/src/lib/i18n/chunks/fr-2.ts`:
- Around line 289-297: Update the French translation for the key
chat.weeklyLimitHit to use cycle-budget terminology instead of weekly wording;
locate the chat.weeklyLimitHit entry and replace "Tu as atteint ta limite
hebdomadaire." with a cycle-consistent phrase such as "Tu as atteint ton budget
pour ce cycle." to align with the surrounding keys (chat.cycle, chat.cycleSpent,
chat.cycleRemaining).
In `@app/src/lib/i18n/chunks/hi-2.ts`:
- Around line 282-289: Update the 'chat.weeklyLimitHit' translation to use
cycle-budget terminology so it aligns with the surrounding keys ('chat.cycle',
'chat.cycleSpent', 'chat.cycleRemaining'); locate the 'chat.weeklyLimitHit'
entry in hi-2.ts and replace the "साप्ताहिक सीमा" wording with a phrase that
references the cycle/budget (consistent tone with 'chat.budgetComplete' and
'chat.cycle'), ensuring the key remains unchanged.
In `@app/src/lib/i18n/chunks/pt-2.ts`:
- Around line 287-295: Update the 'chat.weeklyLimitHit' translation to use
cycle-budget wording to match the rest of the keys (e.g., chat.cycle,
chat.cycleSpent, chat.cycleRemaining, chat.budgetComplete); replace the
weekly-specific phrase ("Você atingiu seu limite semanal.") with a Portuguese
message that communicates the cycle budget has been reached (e.g., using "ciclo"
or "orçamento do ciclo") so all cycle-related strings are consistent.
In `@app/src/lib/i18n/chunks/ru-2.ts`:
- Around line 282-290: The message for 'chat.weeklyLimitHit' is inconsistent
with the cycle-budget terminology used by 'chat.cycle', 'chat.cycleSpent', and
'chat.cycleRemaining'; update the localization for the 'chat.weeklyLimitHit'
entry to mention the cycle-based limit (e.g., replace any "weekly" wording with
"cycle" or equivalent Russian phrasing) so it matches the cycle-budget copy used
elsewhere in this file.
In `@app/src/lib/i18n/chunks/zh-CN-2.ts`:
- Line 265: Update the localization key 'chat.weeklyLimitHit' to use cycle-based
wording instead of "weekly" for the listed locales; specifically in zh-CN-2.ts
replace '已达到每周限制。' with '已使用包含的循环预算。' and apply equivalent cycle-based
translations in fr-2.ts, es-2.ts, pt-2.ts, ru-2.ts, ar-2.ts, hi-2.ts, id-2.ts,
and bn-2.ts so they match the English message "You've used your included cycle
budget." Ensure the exact key 'chat.weeklyLimitHit' is updated in each file and
keep punctuation/period consistent with other locale entries.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: b81aa590-8367-472f-8042-24a24d6dd95d
📒 Files selected for processing (13)
app/src/components/settings/panels/AIPanel.tsxapp/src/components/upsell/GlobalUpsellBanner.tsxapp/src/lib/i18n/chunks/ar-2.tsapp/src/lib/i18n/chunks/bn-2.tsapp/src/lib/i18n/chunks/en-2.tsapp/src/lib/i18n/chunks/es-2.tsapp/src/lib/i18n/chunks/fr-2.tsapp/src/lib/i18n/chunks/hi-2.tsapp/src/lib/i18n/chunks/id-2.tsapp/src/lib/i18n/chunks/pt-2.tsapp/src/lib/i18n/chunks/ru-2.tsapp/src/lib/i18n/chunks/zh-CN-2.tsapp/src/lib/i18n/en.ts
✅ Files skipped from review due to trivial changes (1)
- app/src/lib/i18n/chunks/id-2.ts
🚧 Files skipped from review as they are similar to previous changes (3)
- app/src/components/settings/panels/AIPanel.tsx
- app/src/lib/i18n/en.ts
- app/src/components/upsell/GlobalUpsellBanner.tsx
Code ReviewOverviewClean, well-scoped removal of the 5-hour rate-limit UI driven by backend PR #790. The Strengths
Issues to Fix1. DailyChart percentage-height bug ( Bar divs use Fix: add <div key={p.date} className="flex-1 h-full flex flex-col-reverse" ...>2. calls: normalizeUsd(r.calls), // wrong — calls is a count, not USD
3. Hardcoded English strings in The rebuilt component (~190 lines) drops 4.
Risks5. Silent budget-block UX regression ( The old 6. Missing snake_case fallback tolerance The old normalizer handled Test Coverage7. The rebuilt component has distinct sub-components ( Nits
|
# Conflicts: # app/src/components/settings/panels/billing/InferenceBudget.tsx # app/src/components/upsell/UsageLimitModal.tsx # app/src/pages/Conversations.tsx
- InferenceBudget DailyChart: add h-full to bar column divs so percentage heights resolve against the container (were collapsing to 0) - creditsApi: use Math.round(Number(x)||0) for call-count fields instead of normalizeUsd (which is for currency amounts, not integer counts) - AIPanel: rename "Week remaining" tile label to "Cycle remaining" to match the tooltip i18n key (chat.cycleRemaining) updated in the PR - AIPanel test: update assertion to match new "Cycle remaining" label - TopModels / TopIntegrations: add index suffix to list keys to prevent collisions when provider or model is an empty string
Dark-mode class additions and uiLocale wiring from upstream/main that were accidentally omitted from the merge commit (unstaged during conflict resolution, never re-staged).
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
app/src/components/settings/panels/AIPanel.tsx (1)
1279-1333:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winAlign remaining “Week” labels with cycle-based metrics.
Line 1280 (
Week budget) and Line 1330 (Rows per full week budget) still use week wording, while this panel is now cycle-based. Renaming these avoids mixed terminology in the same card group.Suggested copy fix
- label="Week budget" + label="Cycle budget" ... - label="Rows per full week budget" + label="Rows per full cycle budget"🤖 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 `@app/src/components/settings/panels/AIPanel.tsx` around lines 1279 - 1333, The labels use "Week" but the panel is cycle-based; update the MetricTile and FormulaRow label props to cycle wording—replace the MetricTile with label="Week budget" (symbol: MetricTile at the first occurrence) to label="Cycle budget" and change the FormulaRow with label="Rows per full week budget" (symbol: FormulaRow where value uses estimatedRowsPerBudget) to label="Rows per cycle budget" so all terminology in the card group consistently refers to the cycle.
🧹 Nitpick comments (1)
app/src/pages/__tests__/Conversations.render.test.tsx (1)
618-627: ⚡ Quick winStrengthen the over-budget send-block test with a visible-feedback assertion.
This case currently only checks that
chatSendis suppressed. Add an assertion for the expected over-budget user feedback so UX regressions don’t become silent.🤖 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 `@app/src/pages/__tests__/Conversations.render.test.tsx` around lines 618 - 627, Add an assertion that the over-budget inline feedback is visible after submitting while isAtLimit is true and that it clears when the user continues typing: after calling renderSelectedConversation({ isAtLimit: true }) and submitComposerText(textarea, 'hello at limit'), assert the inline send-error element/text (e.g., the "over budget" message or element with class/name used by the composer send-error) is present/visible using findByText/getByText (or equivalent test-id), then simulate typing (use submitComposerText or userEvent.type) and assert the same element is no longer present (queryByText returns null). Reference: chatSend, renderSelectedConversation, submitComposerText, isAtLimit.
🤖 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.
Outside diff comments:
In `@app/src/components/settings/panels/AIPanel.tsx`:
- Around line 1279-1333: The labels use "Week" but the panel is cycle-based;
update the MetricTile and FormulaRow label props to cycle wording—replace the
MetricTile with label="Week budget" (symbol: MetricTile at the first occurrence)
to label="Cycle budget" and change the FormulaRow with label="Rows per full week
budget" (symbol: FormulaRow where value uses estimatedRowsPerBudget) to
label="Rows per cycle budget" so all terminology in the card group consistently
refers to the cycle.
---
Nitpick comments:
In `@app/src/pages/__tests__/Conversations.render.test.tsx`:
- Around line 618-627: Add an assertion that the over-budget inline feedback is
visible after submitting while isAtLimit is true and that it clears when the
user continues typing: after calling renderSelectedConversation({ isAtLimit:
true }) and submitComposerText(textarea, 'hello at limit'), assert the inline
send-error element/text (e.g., the "over budget" message or element with
class/name used by the composer send-error) is present/visible using
findByText/getByText (or equivalent test-id), then simulate typing (use
submitComposerText or userEvent.type) and assert the same element is no longer
present (queryByText returns null). Reference: chatSend,
renderSelectedConversation, submitComposerText, isAtLimit.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 8c6f4873-6601-4020-90c9-7c541358e7a9
📒 Files selected for processing (17)
app/src/components/chat/TokenUsagePill.tsxapp/src/components/settings/panels/AIPanel.tsxapp/src/components/settings/panels/__tests__/AIPanel.test.tsxapp/src/components/settings/panels/billing/InferenceBudget.tsxapp/src/lib/i18n/chunks/ar-2.tsapp/src/lib/i18n/chunks/bn-2.tsapp/src/lib/i18n/chunks/es-2.tsapp/src/lib/i18n/chunks/fr-2.tsapp/src/lib/i18n/chunks/hi-2.tsapp/src/lib/i18n/chunks/id-2.tsapp/src/lib/i18n/chunks/pt-2.tsapp/src/lib/i18n/chunks/ru-2.tsapp/src/lib/i18n/chunks/zh-CN-2.tsapp/src/lib/i18n/en.tsapp/src/pages/Home.tsxapp/src/pages/__tests__/Conversations.render.test.tsxapp/src/pages/__tests__/Home.test.tsx
✅ Files skipped from review due to trivial changes (2)
- app/src/lib/i18n/en.ts
- app/src/lib/i18n/chunks/fr-2.ts
🚧 Files skipped from review as they are similar to previous changes (10)
- app/src/components/chat/TokenUsagePill.tsx
- app/src/pages/tests/Home.test.tsx
- app/src/components/settings/panels/tests/AIPanel.test.tsx
- app/src/lib/i18n/chunks/ru-2.ts
- app/src/pages/Home.tsx
- app/src/lib/i18n/chunks/ar-2.ts
- app/src/lib/i18n/chunks/es-2.ts
- app/src/lib/i18n/chunks/pt-2.ts
- app/src/components/settings/panels/billing/InferenceBudget.tsx
- app/src/lib/i18n/chunks/id-2.ts
…t keys it-2.ts was added in the main merge with the old rate-limit i18n shape. Replace chat.rateLimitReached / chat.fiveHourLimit / chat.weeklyLimit with chat.cycle / chat.cycleSpent / chat.cycleRemaining to match the English reference and unblock the i18n coverage CI check.
Adds Vitest tests for five files that the coverage CI flagged as under-covered in PR tinyhumansai#2027: - InferenceBudget.test.tsx: full branch coverage for loading, null-usage, cycleBudgetUsd>0/=0, plan discount, UsageBreakdown, DailyChart, TopModels, and TopIntegrations paths - GlobalUpsellBanner.test.tsx: covers at-limit (upgrade), near-limit free-tier (warning with pct), and null-return branches - Home.test.tsx: spy-based useUsageState mock; new test for shouldShowBudgetCompletedMessage=true rendering UsageLimitBanner - Conversations.render.test.tsx: three new tests for the budgetComplete/cycleEndsAt/loading-pulse paths (lines 1871, 1903-1904, 1910) - creditsApi.test.ts: normalizer default-branch tests for normalizeDailyPoint, normalizeModelRow, normalizeIntegrationRow, and normalizePlanSummary missing-field cases
All review feedback addressed and CI passing. Dismissing to unblock merge.
…humansai#2027) Co-authored-by: M3gA-Mind <megamind@mahadao.com>
Summary
checkWindowAvailabilityandassertDailySpendAvailableno-ops.TeamUsagetype + normalizer for the newGET /teams/me/usageshape (cycleSpentUsd,plan{},insights{}with daily series + top-10 models/integrations).PLANSand i18n on the per-call discount story (BASIC 50%, PRO 90%) instead of "X-hour cap" / "weekly limit" framing.Problem
The backend dropped the rolling 5-hour window and daily-cap gates, so the app was still rendering UI for caps that no longer enforce. The
/teams/me/usageresponse also reshaped —cycleLimit5hr,fiveHourCapUsd,fiveHourResetsAt,bypassCycleLimit, andcycleLimit7dayare gone, replaced bycycleSpentUsd, aplanblock, and aninsightsblock. Without this PR the client over-reports caps users no longer hit, and the new spend-insights payload is wasted.Solution
creditsApi.ts: rewroteTeamUsage+normalizeTeamUsageto the new contract (kept Rust handler unchanged — it's a JSON passthrough).useUsageState: droppedisRateLimited/usagePct10hderivations;usagePctnow derives from cycle budget alone.UsageLimitModal.tsxdeleted along with the composer-feedbackshowLimitModalflag. Budget exhaustion still surfaces inline.Conversations.tsx: removed the 5hLimitPill, the rate-limit banner branch, and the modal mount. Cycle pill + tooltip now showcycleSpentUsd / cycleBudgetUsd / remainingUsdonly.AIPanel.tsx: swapped the "5h window" tile for "Cycle total spend" (inference + integration split) and pointed "Week remaining" detail atcycleSpentUsd.InferenceBudget.tsx: rebuilt with cycle-spend bar, breakdown card, daily chart, top models, top integrations, and a discount badge driven byplan.discountVsPayAsYouGoPercent.Home.tsx,TokenUsagePill.tsx,GlobalUpsellBanner.tsx: pruned rate-limit branches; useusagePct.billingHelpers.ts+ en/zh-CN/id i18n: rate-limit-flavoured strings out, cycle/discount strings in.Submission Checklist
pnpm testpasses 2500 tests; touched files all have updated unit tests for the new shape (creditsApi.test.ts,useUsageState.test.ts,AIPanel.test.tsx,Conversations.render.test.tsx,billingApi.test.ts,billingHelpers.test.ts,composerSendDecision.test.ts,Home.test.tsx).Impact
team_get_usageis already a JSON passthrough — the new shape flows through unchanged).Related
AI Authored PR Metadata (required for Codex/Linear PRs)
Linear Issue
Commit & Branch
feat/drop-rate-limits-show-usage2ab8f7dfbc0f10f771a00b83bdb0e2a55bb05a66Validation Run
pnpm --filter openhuman-app format:checkpnpm typecheckpnpm --filter openhuman-app test -- --run— 2500 passed, 3 skippedValidation Blocked
command:N/Aerror:N/Aimpact:N/ABehavior Changes
Parity Contract
BalanceService.canAfford.normalizeTeamUsagereturns safe defaults (zeroed insights, FREE plan summary) for empty / malformed payloads, matching the previous defensive contract.Duplicate / Superseded PR Handling
Summary by CodeRabbit
New Features
Bug Fixes & Improvements
UI/UX Updates