Skip to content

fix(cli): surface 429 rate limit cool-down and countdown in loading indicator - #30012

Open
urielefrenvirtusa wants to merge 10 commits into
google-gemini:mainfrom
urielefrenvirtusa:b_562498203
Open

urielefrenvirtusa wants to merge 10 commits into
google-gemini:mainfrom
urielefrenvirtusa:b_562498203

Conversation

@urielefrenvirtusa

Copy link
Copy Markdown
Contributor

Summary

Improves the terminal user experience during HTTP 429 (Rate Limit / Quota Exceeded) events by immediately surfacing a cool-down notice on Attempt 1 and rendering an active, second-by-second visual countdown ticker in the loading indicator.

Details

  • Early Visibility for Rate Limits: In default low error verbosity mode, generic retries are suppressed on Attempt 1 until later retries. For rate limits (429 status code, QUOTA_EXCEEDED, RESOURCE_EXHAUSTED), this suppression caused perceived "silent hangs". We now detect rate limit errors via isRateLimitRetry() and surface them immediately on Attempt 1.
  • Active Countdown Ticker: useLoadingIndicator now manages an active 1-second countdown interval while isTimerActive is true, decrementing remaining seconds (delayMs / 1000 down to 1s) to give continuous visual feedback:
    Rate limit reached. Cooling down... Retrying in 12s (Attempt 1/3)
  • Multi-Attempt Clean Reset: When subsequent retry attempts arrive, the countdown cleanly resets to the new backoff duration.
  • Status Code Propagation: Enriched RetryAttemptPayload in packages/core with optional status?: number, and forwarded status: getErrorStatus(error) from geminiChat.ts, baseLlmClient.ts, and client.ts.
  • Zero Regression / Full Backward Compatibility: Generic network retries (e.g., 500s) maintain their exact existing behavior and strings. No new eslint-disable rules introduced.

Related Issues

Fixes #29357

How to Validate

  1. Run the dedicated 429 countdown unit test suite:
    npm test -w @google/gemini-cli -- src/ui/hooks/useLoadingIndicator_429.test.tsx
  2. Run related UI and loading indicator suites:
    npm test -w @google/gemini-cli -- src/ui/hooks/useLoadingIndicator.test.tsx src/ui/components/LoadingIndicator.test.tsx src/ui/components/StatusRow.test.tsx
  3. Run core retry tests:
    npm test -w @google/gemini-cli-core -- src/utils/retry.test.ts src/core/geminiChat_network_retry.test.ts

Pre-Merge Checklist

  • Updated relevant documentation and README (if needed)
  • Added/updated tests (if needed)
  • Noted breaking changes (if any)
  • Validated on required platforms/methods:
    • MacOS
      • npm run
      • npx
      • Docker
      • Podman
      • Seatbelt
    • Windows
      • npm run
      • npx
      • Docker
    • Linux
      • npm run
      • npx
      • Docker

…ndicator

- Add isRateLimitRetry helper and active countdown ticker to useLoadingIndicator
- Surface 429 rate limit cool-downs immediately on Attempt 1 in default low error verbosity
- Propagate optional HTTP status code on RetryAttemptPayload from core
@urielefrenvirtusa
urielefrenvirtusa requested a review from a team as a code owner October 28, 2026 18:23
@github-actions github-actions Bot added the size/l A large sized PR label Oct 28, 2026
@github-actions

github-actions Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

📊 PR Size: size/L

  • Lines changed: 491
  • Additions: +486
  • Deletions: -5
  • Files changed: 6

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, 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 terminal user experience during rate-limited API requests by surfacing explicit cool-down notices and a real-time countdown ticker. By improving error propagation and detection, the CLI now provides immediate feedback instead of appearing to hang during initial retry attempts, while maintaining backward compatibility for other network error types.

Highlights

  • Rate Limit UX Improvements: Introduced an active countdown timer in the loading indicator when a 429 (Rate Limit) error occurs, providing immediate visual feedback to the user.
  • Enhanced Error Detection: Added isRateLimitRetry to detect rate limit errors on the first attempt, preventing the perceived 'silent hang' previously caused by suppressing retries in low verbosity mode.
  • Data Enrichment: Updated RetryAttemptPayload to include an optional status field, populated by getErrorStatus across core client modules to better identify HTTP 429 events.
Using Gemini Code Assist

The 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 /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the 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 .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. 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.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩

@urielefrenvirtusa

Copy link
Copy Markdown
Contributor Author

/Gemini review

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces a cool-down countdown UX for 429 rate limit retries by extracting the HTTP error status in core clients and implementing a countdown timer in the CLI's loading indicator hook, accompanied by a new test suite. The review feedback correctly identifies a bug where the countdown timer resets and jumps when paused or resumed due to the effect resetting state on inactivity. To resolve this, the reviewer suggests a simplified state adjustment pattern that preserves the countdown state when paused, along with a corresponding test improvement to properly validate the pause/resume behavior.

Comment thread packages/cli/src/ui/hooks/useLoadingIndicator.ts Outdated
Comment thread packages/cli/src/ui/hooks/useLoadingIndicator.ts Outdated
Comment thread packages/cli/src/ui/hooks/useLoadingIndicator_429.test.tsx

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces a countdown and cool-down UX for 429 rate limit retries in the loading indicator. It adds status code tracking to retry events across the core clients and implements a countdown timer in the useLoadingIndicator hook, along with comprehensive unit tests. The review feedback correctly identifies a bug where pausing updates resets the countdown timer, as well as a React rule violation caused by reading a ref during rendering. It is recommended to refactor the hook to use derived state to safely track the previous retry status and preserve the countdown state when paused.

Comment thread packages/cli/src/ui/hooks/useLoadingIndicator.ts Outdated
Comment thread packages/cli/src/ui/hooks/useLoadingIndicator.ts Outdated
@gemini-cli gemini-cli Bot added the area/core Issues related to User Interface, OS Support, Core Functionality label Oct 28, 2026
- Refactor useLoadingIndicator countdown to derive state when retryStatus changes
- Prevent countdown resetting to initial delay on pause or resume
- Remove prevRetryStatusRef to avoid reading refs during render
- Update Case 6 test to verify countdown freezing and resuming after running
@urielefrenvirtusa

Copy link
Copy Markdown
Contributor Author

/Gemini review

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces a cool-down countdown UX for 429 rate limit retries. It adds a status field to the RetryAttemptPayload across the core LLM clients to propagate HTTP status codes, implements a countdown timer and rate-limit detection in the useLoadingIndicator hook, and adds comprehensive unit tests. The review feedback suggests optimizing the countdown useEffect by using destructured primitive properties of retryStatus as stable dependencies to avoid unnecessary interval resets. Additionally, it recommends aligning the rate-limit attempt numbering with standard retries by using attempt + 1 and safely handling optional properties with default values.

Comment thread packages/cli/src/ui/hooks/useLoadingIndicator.ts Outdated
Comment thread packages/cli/src/ui/hooks/useLoadingIndicator.ts Outdated
…ttempt numbering

- Destructure attempt, delayMs, and model as primitive dependencies for countdown interval
- Align rate-limit attempt numbering with standard retries by using attempt + 1
- Use null-safe property access with default fallbacks for retryStatus
@urielefrenvirtusa

Copy link
Copy Markdown
Contributor Author

/Gemini review

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces a cool-down countdown UX for 429 rate limit retries in the CLI loading indicator. It adds a status field to the RetryAttemptPayload across the core LLM clients to capture HTTP error statuses, implements rate-limit detection and countdown logic in the useLoadingIndicator hook, and adds comprehensive unit tests. The review feedback suggests improving the robustness of the isSameRetry comparison by including status and error fields, and optimizing performance in the terminal environment by only running the countdown interval when a rate limit is actually active to prevent unnecessary re-renders.

Comment thread packages/cli/src/ui/hooks/useLoadingIndicator.ts Outdated
Comment thread packages/cli/src/ui/hooks/useLoadingIndicator.ts Outdated
Comment thread packages/cli/src/ui/hooks/useLoadingIndicator.ts Outdated
…omparison

- Include status and error in isSameRetry comparison
- Restrict countdown interval to rate limit retries only to avoid unnecessary renders
- Remove duplicate isRateLimit definition
@urielefrenvirtusa

Copy link
Copy Markdown
Contributor Author

/Gemini review

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces a 429 Rate Limit cool-down countdown UX to the CLI loading indicator. It updates the core clients (BaseLlmClient, GeminiClient, and GeminiChat) to propagate the HTTP error status code within the RetryAttemptPayload, allowing the useLoadingIndicator hook to detect rate limits and run a countdown timer. Comprehensive tests are also added to verify this behavior. Feedback on the changes highlights a redundant attempt === 0 guard check in the loading indicator hook's effect, and a bug in the test cleanup where vi.runOnlyPendingTimers is referenced but not invoked.

Comment thread packages/cli/src/ui/hooks/useLoadingIndicator.ts Outdated
Comment thread packages/cli/src/ui/hooks/useLoadingIndicator_429.test.tsx Outdated
…rs in test

- Remove redundant attempt === 0 check from useEffect guard
- Invoke vi.runOnlyPendingTimers() inside act in test afterEach cleanup before restoring real timers
@urielefrenvirtusa

Copy link
Copy Markdown
Contributor Author

/Gemini review

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces support for tracking and displaying a cool-down countdown when encountering HTTP 429 rate limit errors. It updates the core LLM clients (BaseLlmClient, GeminiClient, and GeminiChat) to extract and include the HTTP status code in retry attempt payloads. In the CLI UI, the useLoadingIndicator hook is updated to detect rate limits, manage a countdown timer, and display a user-friendly cooling-down message. Comprehensive tests are also added to verify this countdown behavior under various scenarios. The review feedback correctly identifies a potential background resource leak in the countdown useEffect within useLoadingIndicator.ts, where the interval is not cleared once the countdown reaches its minimum value, and provides a clear suggestion to resolve it.

Comment thread packages/cli/src/ui/hooks/useLoadingIndicator.ts Outdated
- Guard countdown interval with countdownSeconds === null || countdownSeconds <= 1
- Include countdownSeconds in dependency array so interval terminates cleanly when countdown completes
@urielefrenvirtusa

Copy link
Copy Markdown
Contributor Author

/Gemini review

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces a cool-down countdown UX for 429 Rate Limit retries. It adds an isRateLimitRetry helper and countdown logic to the useLoadingIndicator hook in packages/cli, updating the UI to display a remaining seconds countdown during rate limit backoffs. To support this, the RetryAttemptPayload in packages/core has been updated to include the HTTP status code retrieved via getErrorStatus(error). Comprehensive unit tests have also been added to verify the countdown behavior under various scenarios. No review comments were provided, and the implementation looks solid, so I have no feedback to provide.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/core Issues related to User Interface, OS Support, Core Functionality size/l A large sized PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature Request: Improve 429 (Rate Limit) UX via CLI-Level "Cool-Down" Wrapper & Terminal Countdown

1 participant