Skip to content

Conversation

@SandyTao520
Copy link
Collaborator

@SandyTao520 SandyTao520 commented Nov 19, 2025

TLDR

This PR fixes a race condition where restoring the user's prompt after a 'Context Window Overflow' event would sometimes fail or restore an outdated message.

Dive Deeper

When a user submits a prompt that exceeds the context window, the system triggers a cancellation and attempts to restore the prompt to the input buffer. Previously, this logic relied on userMessages state, which is updated asynchronously via a useEffect hook.

The ContextWindowWillOverflow event fires almost immediately after submission, often before the userMessages state has had a chance to synchronize with the new history item. As a result, the restoration logic would read stale state, effectively 'restoring' the previous prompt instead of the one just submitted.

This fix introduces a state-based synchronization mechanism:

  1. A new state pendingPromptRestore flags when a restoration is requested.
  2. A useEffect hook watches this flag and compares the latest userMessages entry with the actual source of truth (historyManager.history).
  3. The prompt is restored to the input buffer only when the states match, ensuring we always restore the correct, up-to-date message.

This approach eliminates the race condition by deferring the UI update until the data is consistent.

Reviewer Test Plan

To verify this fix:

  1. Submit a long prompt that exceeds this limit (@packages/ hello)
  2. Verify: The input buffer should correctly reappear with the exact text you just submitted.

Testing Matrix

🍏 🪟 🐧
npm run
npx
Docker
Podman - -
Seatbelt - -

Linked issues / bugs

Resolves a race condition in prompt restoration logic.

@SandyTao520 SandyTao520 requested a review from a team as a code owner November 19, 2025 23:59
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @SandyTao520, 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 addresses a critical race condition within the UI's prompt restoration feature. When a user's input exceeds the context window, the system attempts to restore the prompt to the input buffer. Previously, this process could fail or restore an incorrect, outdated message due to the asynchronous nature of state updates. The implemented solution introduces a robust state-based synchronization mechanism, ensuring that the prompt is only restored once the underlying message history is consistent, thereby guaranteeing the correct and most recent prompt is always presented to the user.

Highlights

  • Race Condition Fix: Resolves a race condition where the user's prompt was sometimes restored incorrectly or with outdated text after a 'Context Window Overflow' event.
  • Asynchronous State Handling: The previous logic relied on asynchronously updated userMessages state, leading to stale data being used for prompt restoration.
  • New Synchronization Mechanism: Introduces a pendingPromptRestore state and a useEffect hook to defer prompt restoration until the userMessages state is fully synchronized with the historyManager.history, ensuring the correct, up-to-date message is always restored.
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 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 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

  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.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

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 aims to fix a race condition in prompt restoration after a context window overflow. The proposed solution, while addressing the original issue, introduces a new potential race condition. My review includes a critical comment on the implementation in AppContainer.tsx, detailing this new issue and proposing a simpler, more robust alternative. The changes to the test file AppContainer.test.tsx are appropriate for testing the asynchronous nature of the fix.

Comment on lines +759 to +782
useEffect(() => {
if (pendingPromptRestore) {
// Check if userMessages is up to date with historyManager
const lastHistoryItem = historyManager.history.findLast(
(item) => item.type === 'user' && item.text,
);
const lastUserMessage = userMessages.at(-1);

if (
lastHistoryItem &&
lastHistoryItem.text === lastUserMessage &&
lastUserMessage
) {
buffer.setText(lastUserMessage);
setPendingPromptRestore(false);
}
}
}, [
pendingPromptRestore,
userMessages,
historyManager.history,
buffer,
setPendingPromptRestore,
]);
Copy link
Contributor

Choose a reason for hiding this comment

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

critical

While this useEffect approach does fix the original race condition, it introduces a new, more subtle one. If a user submits a second prompt very quickly after the one that caused the context overflow, this logic could restore the second prompt instead of the one that overflowed. This happens because the effect always looks for the latest user message in historyManager.history and userMessages to be in sync, but it doesn't track which message was supposed to be restored.

A simpler and more robust solution would be to avoid the useEffect and the pendingPromptRestore state altogether. You can directly access the correct history in the onCancelSubmit handler.

I suggest the following changes:

  1. Remove the pendingPromptRestore state.
  2. Remove this useEffect block.
  3. Update cancelHandlerRef.current to get the last message directly from historyManager.history and add historyManager.history to its useCallback dependency array.

Here's how cancelHandlerRef.current could look:

cancelHandlerRef.current = useCallback(
  (shouldRestorePrompt: boolean = true) => {
    const pendingHistoryItems = [
      ...pendingSlashCommandHistoryItems,
      ...pendingGeminiHistoryItems,
    ];
    if (isToolExecuting(pendingHistoryItems)) {
      buffer.setText(''); // Just clear the prompt
      return;
    }

    let textToSet = '';
    if (shouldRestorePrompt) {
      const lastHistoryItem = historyManager.history.findLast(
        (item) => item.type === 'user' && item.text,
      );
      textToSet = lastHistoryItem?.text || '';
    }

    const queuedText = getQueuedMessagesText();
    if (queuedText) {
      textToSet = textToSet ? `${textToSet}\n\n${queuedText}` : queuedText;
      clearQueue();
    }

    if (textToSet || !shouldRestorePrompt) {
      buffer.setText(textToSet);
    }
  },
  [
    buffer,
    getQueuedMessagesText,
    clearQueue,
    pendingSlashCommandHistoryItems,
    pendingGeminiHistoryItems,
    historyManager.history, // Add this dependency
  ],
);

This approach is more direct, less complex, and avoids the potential for new race conditions.

@github-actions
Copy link

Size Change: +671 B (0%)

Total Size: 21.1 MB

ℹ️ View Unchanged
Filename Size Change
./bundle/gemini.js 21.1 MB +671 B (0%)
./bundle/sandbox-macos-permissive-closed.sb 1.03 kB 0 B
./bundle/sandbox-macos-permissive-open.sb 890 B 0 B
./bundle/sandbox-macos-permissive-proxied.sb 1.31 kB 0 B
./bundle/sandbox-macos-restrictive-closed.sb 3.29 kB 0 B
./bundle/sandbox-macos-restrictive-open.sb 3.36 kB 0 B
./bundle/sandbox-macos-restrictive-proxied.sb 3.56 kB 0 B

compressed-size-action

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant