feat: Limit auto-claude window usage based on budget #1907
feat: Limit auto-claude window usage based on budget #1907eyalk11 wants to merge 1 commit intoAndyMik90:developfrom
Conversation
- Add `budgetCapPercent` setting: a single unified slider that caps both
session and weekly thresholds, preventing usage beyond the configured
percentage of the plan (e.g. 80% budget cap).
- Add `noExtraUsage` toggle: marks an account unavailable once either
usage limit hits 100%, preventing Anthropic extra-usage (pay-per-use
overage) from being consumed.
- Apply both settings in profile-scorer (availability checks, fallback
scoring, unified account scoring, proactive switch logic) and in
usage-monitor threshold checks.
- Add UI controls (budget cap slider + toggle) in AccountSettings below
the weekly threshold slider, visible when proactive monitoring is on.
- Add i18n keys for both new controls in en/fr settings locales.
- Move budget cap and noExtraUsage controls into a dedicated "Usage Limits"
section visible regardless of account count (no longer gated by totalAccounts > 1).
- Budget cap and noExtraUsage now work independently of the auto-switch master
toggle, so single-account users can also enforce plan limits.
- When a budget limit is hit and no alternative account is available, emit
budget-exhausted from UsageMonitor → initializeUsageMonitorForwarding calls
agentManager.killAll() to stop all running agents immediately.
- Pass agentManager into initializeUsageMonitorForwarding in index.ts (both
the primary and fallback init paths).
|
|
📝 WalkthroughWalkthroughThis PR introduces budget cap and noExtraUsage policies for Claude auto-switch settings. It adds optional budgetCapPercent (0-100) and noExtraUsage (boolean) fields that constrain usage thresholds, emit a budget-exhausted event when limits are reached with no alternatives, kill running agents, and expose UI controls for configuring these policies. Changes
Sequence Diagram(s)sequenceDiagram
participant UsageMonitor as Usage Monitor
participant ProfileScorer as Profile Scorer
participant ProactiveSwap as Proactive Swap
participant AgentManager as Agent Manager
participant TerminalHandlers as Terminal Handlers
participant Renderer as Renderer
UsageMonitor->>UsageMonitor: checkUsageAndSwap()
UsageMonitor->>ProfileScorer: Evaluate effective thresholds<br/>(budgetCapPercent, noExtraUsage)
ProfileScorer-->>UsageMonitor: exceeds threshold at 100%?
alt Budget Policy Active & No Alternatives
UsageMonitor->>ProactiveSwap: performProactiveSwap(stopIfExhausted=true)
ProactiveSwap-->>UsageMonitor: No alternatives found
UsageMonitor->>UsageMonitor: Emit budget-exhausted event
UsageMonitor->>TerminalHandlers: Relay budget-exhausted
TerminalHandlers->>AgentManager: killAll()
AgentManager-->>TerminalHandlers: Cleanup complete
TerminalHandlers->>Renderer: Emit budget_exhausted to UI
else Alternatives Available
UsageMonitor->>ProactiveSwap: Switch to alternative profile
ProactiveSwap-->>UsageMonitor: Switch successful
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request enhances the Claude profile management system by introducing robust usage limit controls. It allows users to define a budget cap for both session and weekly usage and to prevent extra usage beyond their plan limits. These new settings are deeply integrated into the system's logic for determining profile availability and proactive switching, and are exposed through a new, dedicated section in the user interface. The changes ensure that agents are stopped if budget limits are hit and no alternative accounts are available, providing better cost control and preventing unexpected overages. Highlights
Changelog
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
🎉 Thanks for your first PR!
A maintainer will review it soon. Please make sure:
- Your branch is synced with
develop - CI checks pass
- You've followed our contribution guide
Welcome to the Auto Claude community!
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
| const effectiveSession = settings.budgetCapPercent !== undefined | ||
| ? Math.min(baseSession, settings.budgetCapPercent) | ||
| : baseSession; | ||
| const effectiveWeekly = settings.budgetCapPercent !== undefined | ||
| ? Math.min(baseWeekly, settings.budgetCapPercent) | ||
| : baseWeekly; |
There was a problem hiding this comment.
Bug: The UI allows setting budgetCapPercent to 0. This creates an impossible 0% usage threshold, marking all accounts as unavailable and triggering termination of all running agents.
Severity: HIGH
Suggested Fix
Prevent the budgetCapPercent from being set to 0. This can be done by adjusting the min value of the slider in the UI from 0 to a more sensible minimum, such as 1 or 5.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: apps/frontend/src/main/claude-profile/usage-monitor.ts#L1113-L1118
Potential issue: The UI slider for `budgetCapPercent` in `AccountSettings.tsx` allows a
minimum value of 0. When this value is set, the logic in `usage-monitor.ts` calculates
effective usage thresholds using `Math.min(baseThreshold, 0)`, which results in 0.
Consequently, any account with usage greater than 0% is considered to have exceeded its
budget. This leads to all accounts being marked as unavailable. When the system tries to
find an alternative account and fails, it emits a `budget-exhausted` event, which in
turn calls `agentManager.killAll()` and terminates all active user agents.
Did we get this right? 👍 / 👎 to inform future reviews.
There was a problem hiding this comment.
Code Review
This pull request introduces a budget cap feature to limit token usage by auto-claude. It adds budgetCapPercent and noExtraUsage settings, which are correctly implemented across the profile scoring, usage monitoring, and UI components. The logic to stop agents when the budget is exhausted and no alternative accounts are available is also well-implemented. My main feedback is to refactor some duplicated code for calculating effective thresholds into a shared helper function to improve maintainability.
| // Effective thresholds: budget cap (if set) acts as a ceiling on both thresholds | ||
| const effectiveWeeklyThreshold = settings.budgetCapPercent !== undefined | ||
| ? Math.min(settings.weeklyThreshold, settings.budgetCapPercent) | ||
| : settings.weeklyThreshold; | ||
| const effectiveSessionThreshold = settings.budgetCapPercent !== undefined | ||
| ? Math.min(settings.sessionThreshold, settings.budgetCapPercent) | ||
| : settings.sessionThreshold; |
There was a problem hiding this comment.
To improve maintainability and adhere to the DRY (Don't Repeat Yourself) principle, consider extracting the logic for calculating effective thresholds into a helper function. This logic is duplicated in several places in this file (calculateFallbackScore, scoreUnifiedAccount, shouldProactivelySwitch) and also in apps/frontend/src/main/claude-profile/usage-monitor.ts in the checkThresholdsExceeded function.
A shared utility function could look like this:
function getEffectiveThresholds(settings: ClaudeAutoSwitchSettings) {
const baseSession = settings.sessionThreshold ?? 95;
const baseWeekly = settings.weeklyThreshold ?? 99;
const effectiveSessionThreshold = settings.budgetCapPercent !== undefined
? Math.min(baseSession, settings.budgetCapPercent)
: baseSession;
const effectiveWeeklyThreshold = settings.budgetCapPercent !== undefined
? Math.min(baseWeekly, settings.budgetCapPercent)
: baseWeekly;
return { effectiveSessionThreshold, effectiveWeeklyThreshold };
}There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/frontend/src/main/claude-profile/usage-monitor.ts (1)
1927-1979:⚠️ Potential issue | 🔴 CriticalBudget exhaustion can be missed because alternatives aren’t policy-filtered.
At Line 1928-Line 1959, alternatives are collected by auth/availability only. If every alternative is already over budget/no-extra limits,
unifiedAccounts.lengthis still non-zero, so thebudget-exhaustedbranch at Line 1965 may never run.Suggested fix
private async performProactiveSwap( @@ ): Promise<void> { const profileManager = getClaudeProfileManager(); + const settings = profileManager.getAutoSwitchSettings(); const excludeIds = new Set([currentProfileId, ...additionalExclusions]); @@ for (const profile of oauthProfiles) { if (!excludeIds.has(profile.id)) { + if (stopIfExhausted && profile.usage) { + const session = profile.usage.sessionUsagePercent; + const weekly = profile.usage.weeklyUsagePercent; + const budgetCap = settings.budgetCapPercent; + const overBudgetCap = budgetCap !== undefined && (session >= budgetCap || weekly >= budgetCap); + const overNoExtra = !!settings.noExtraUsage && (session >= 100 || weekly >= 100); + if (overBudgetCap || overNoExtra) { + continue; + } + } const unifiedId = `oauth-${profile.id}`;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/frontend/src/main/claude-profile/usage-monitor.ts` around lines 1927 - 1979, After collecting oauth and api alternatives into unifiedAccounts (from profileManager.getProfilesSortedByAvailability and loadProfilesFile), filter unifiedAccounts by the same budget/policy check used for the current profile so accounts that are over-budget or have "no extra limits" are excluded; e.g. call the existing budget-check helper (create or reuse a helper like isAccountWithinBudget or isProfileAllowedByPolicy) for each unifiedAccount.unifiedId or id and only keep those that pass before checking unifiedAccounts.length, then if filtered list is empty follow the stopIfExhausted -> emit('budget-exhausted', ...) or emit('proactive-swap-failed', ...) branches accordingly (also reference excludeIds and additionalExclusions when emitting).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/frontend/src/main/claude-profile/usage-monitor.ts`:
- Around line 1105-1124: The function checkThresholdsExceeded currently seeds
baseSession/baseWeekly to 95/99 which causes noExtraUsage-only mode to trigger
before 100%; change the baseline when settings.noExtraUsage is true so
thresholds default to 100 instead of 95/99. Concretely, in
checkThresholdsExceeded adjust how baseSession and baseWeekly are computed (or
override effectiveSession/effectiveWeekly) to use 100 when settings.noExtraUsage
is true, then apply the budgetCapPercent ceiling (Math.min) only afterwards if
budgetCapPercent is provided; keep the rest of the
sessionExceeded/weeklyExceeded checks unchanged and reference the existing
symbols baseSession, baseWeekly, effectiveSession, effectiveWeekly, and
settings.noExtraUsage.
---
Outside diff comments:
In `@apps/frontend/src/main/claude-profile/usage-monitor.ts`:
- Around line 1927-1979: After collecting oauth and api alternatives into
unifiedAccounts (from profileManager.getProfilesSortedByAvailability and
loadProfilesFile), filter unifiedAccounts by the same budget/policy check used
for the current profile so accounts that are over-budget or have "no extra
limits" are excluded; e.g. call the existing budget-check helper (create or
reuse a helper like isAccountWithinBudget or isProfileAllowedByPolicy) for each
unifiedAccount.unifiedId or id and only keep those that pass before checking
unifiedAccounts.length, then if filtered list is empty follow the
stopIfExhausted -> emit('budget-exhausted', ...) or
emit('proactive-swap-failed', ...) branches accordingly (also reference
excludeIds and additionalExclusions when emitting).
ℹ️ Review info
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (9)
apps/frontend/src/main/claude-profile/profile-scorer.tsapps/frontend/src/main/claude-profile/profile-storage.tsapps/frontend/src/main/claude-profile/usage-monitor.tsapps/frontend/src/main/index.tsapps/frontend/src/main/ipc-handlers/terminal-handlers.tsapps/frontend/src/renderer/components/settings/AccountSettings.tsxapps/frontend/src/shared/i18n/locales/en/settings.jsonapps/frontend/src/shared/i18n/locales/fr/settings.jsonapps/frontend/src/shared/types/agent.ts
| private checkThresholdsExceeded( | ||
| usage: ClaudeUsageSnapshot, | ||
| settings: { sessionThreshold?: number; weeklyThreshold?: number } | ||
| settings: { sessionThreshold?: number; weeklyThreshold?: number; budgetCapPercent?: number; noExtraUsage?: boolean } | ||
| ): { sessionExceeded: boolean; weeklyExceeded: boolean; anyExceeded: boolean } { | ||
| const sessionExceeded = usage.sessionPercent >= (settings.sessionThreshold ?? 95); | ||
| const weeklyExceeded = usage.weeklyPercent >= (settings.weeklyThreshold ?? 99); | ||
| const baseSession = settings.sessionThreshold ?? 95; | ||
| const baseWeekly = settings.weeklyThreshold ?? 99; | ||
|
|
||
| // Budget cap acts as a ceiling on both thresholds | ||
| const effectiveSession = settings.budgetCapPercent !== undefined | ||
| ? Math.min(baseSession, settings.budgetCapPercent) | ||
| : baseSession; | ||
| const effectiveWeekly = settings.budgetCapPercent !== undefined | ||
| ? Math.min(baseWeekly, settings.budgetCapPercent) | ||
| : baseWeekly; | ||
|
|
||
| // noExtraUsage: also flag when hitting 100% | ||
| const sessionExceeded = usage.sessionPercent >= effectiveSession || | ||
| (!!settings.noExtraUsage && usage.sessionPercent >= 100); | ||
| const weeklyExceeded = usage.weeklyPercent >= effectiveWeekly || | ||
| (!!settings.noExtraUsage && usage.weeklyPercent >= 100); |
There was a problem hiding this comment.
Budget-only mode is still enforcing proactive thresholds.
Line 1109 and Line 1110 always seed 95/99 (or configured) thresholds, so noExtraUsage-only mode can trigger exhaustion flow before 100%. That contradicts the “stop at 100%” behavior.
Suggested fix
- private checkThresholdsExceeded(
+ private checkThresholdsExceeded(
usage: ClaudeUsageSnapshot,
- settings: { sessionThreshold?: number; weeklyThreshold?: number; budgetCapPercent?: number; noExtraUsage?: boolean }
+ settings: { sessionThreshold?: number; weeklyThreshold?: number; budgetCapPercent?: number; noExtraUsage?: boolean },
+ useProactiveThresholds: boolean
): { sessionExceeded: boolean; weeklyExceeded: boolean; anyExceeded: boolean } {
- const baseSession = settings.sessionThreshold ?? 95;
- const baseWeekly = settings.weeklyThreshold ?? 99;
+ const baseSession = useProactiveThresholds ? (settings.sessionThreshold ?? 95) : 100;
+ const baseWeekly = useProactiveThresholds ? (settings.weeklyThreshold ?? 99) : 100;- const thresholds = this.checkThresholdsExceeded(usage, settings);
+ const thresholds = this.checkThresholdsExceeded(usage, settings, isProactiveEnabled);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/frontend/src/main/claude-profile/usage-monitor.ts` around lines 1105 -
1124, The function checkThresholdsExceeded currently seeds
baseSession/baseWeekly to 95/99 which causes noExtraUsage-only mode to trigger
before 100%; change the baseline when settings.noExtraUsage is true so
thresholds default to 100 instead of 95/99. Concretely, in
checkThresholdsExceeded adjust how baseSession and baseWeekly are computed (or
override effectiveSession/effectiveWeekly) to use 100 when settings.noExtraUsage
is true, then apply the budgetCapPercent ceiling (Math.min) only afterwards if
budgetCapPercent is provided; keep the rest of the
sessionExceeded/weeklyExceeded checks unchanged and reference the existing
symbols baseSession, baseWeekly, effectiveSession, effectiveWeekly, and
settings.noExtraUsage.
budgetCapPercentsetting: a single unified slider that caps both session and weekly thresholds, preventing usage beyond the configured percentage of the plan (e.g. 80% budget cap).noExtraUsagetoggle: marks an account unavailable once either usage limit hits 100%, preventing Anthropic extra-usage (pay-per-use overage) from being consumed.Base Branch
developbranch (required for all feature/fix PRs)main(hotfix only - maintainers)Description
It makes auto-claude stop when reaches X% of allowed tokens in the 5-hours window . Also, make auto-claude not consume extra-usage even if available.
Looks like that :
Related Issue
Closes #
Type of Change
Area
Commit Message Format
Follow conventional commits:
<type>: <subject>Types: feat, fix, docs, style, refactor, test, chore
Example:
feat: add user authentication systemAI Disclosure
Tool(s) used:
Testing level:
Untested -- AI output not yet verified
[ X ] Lightly tested -- ran the app / spot-checked key paths . I checked that it works.
Fully tested -- all tests pass, manually verified behavior
[ X] I understand what this PR does ** but not how the underlying code works**
Checklist
developbranchPlatform Testing Checklist
CRITICAL: This project supports Windows, macOS, and Linux. Platform-specific bugs are a common source of breakage.
platform/module instead of directprocess.platformchecksfindExecutable()or platform abstractions)If you only have access to one OS: CI now tests on all platforms. Ensure all checks pass before submitting.
CI/Testing Requirements
Screenshots
Feature Toggle
use_feature_nameNew Features
Documentation