Skip to content

feat: Implement session persistence for CLI chat history#4070

Closed
JiechengZhao wants to merge 22 commits intogoogle-gemini:mainfrom
JiechengZhao:feat/session-persistence
Closed

feat: Implement session persistence for CLI chat history#4070
JiechengZhao wants to merge 22 commits intogoogle-gemini:mainfrom
JiechengZhao:feat/session-persistence

Conversation

@JiechengZhao
Copy link
Copy Markdown

@JiechengZhao JiechengZhao commented Jul 13, 2025

TLDR

This pull request refactors the session persistence logic out of the main App.tsx component and into a new, dedicated useSessionPersistence hook. This improves code organization and separation of concerns. Comprehensive unit tests for the new hook have also been added and enabled.

Dive Deeper

The session persistence logic, which handles saving chat history on exit and reloading it on startup, was previously implemented directly within the App.tsx component using a pair of useEffect hooks. This cluttered the main component with side effects and file system logic that were not directly related to its rendering responsibilities.

By extracting this functionality into useSessionPersistence.ts, we create a clean, reusable, and independently testable piece of logic, adhering to React best practices. The App.tsx component is now simpler, only needing to invoke the new hook to enable the feature.

The accompanying test file, useSessionPersistence.test.ts, has been corrected and activated. It thoroughly tests the hook's behavior by mocking the fs and process modules, ensuring that history is correctly loaded, saved, and filtered without performing actual file I/O during test execution.

Additionally, a new MessageType.TOOL_GROUP has been added to types.ts.

Reviewer Test Plan

  1. Pull down the feat/session-persistence branch.
  2. Run npm install to ensure all dependencies are installed.
  3. Run the full preflight check with npm run preflight. All tests, linting, and build steps should pass.
  4. Start the application using npx gemini.
  5. Enter a few prompts to build up a chat history.
  6. Exit the application (e.g., using Ctrl+C twice).
  7. Verify that a .gemini/session.json file was created in your current directory and that it contains the history of your user prompts and Gemini's responses.
  8. Restart the application with npx gemini.
  9. Confirm that the history from the previous session is successfully loaded into the UI.
  10. To test the opt-out functionality, disable session.persistence in your Gemini config file, then repeat the steps above. Confirm that history is no longer saved or loaded.

Testing Matrix

npm run
npx
Docker
Podman - -
Seatbelt - -

Linked issues / bugs

Closes #4205

@JiechengZhao JiechengZhao requested a review from a team as a code owner July 13, 2025 22:57
@google-cla
Copy link
Copy Markdown

google-cla Bot commented Jul 13, 2025

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

Copy link
Copy Markdown
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.

Summary of Changes

Hello @JiechengZhao, 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 introduces a significant new feature: the ability to persist CLI chat history. The core change involves refactoring the persistence mechanism into a dedicated, testable React hook, useSessionPersistence, which handles the loading of previous sessions on startup and saving the current session upon exit. This enhances the user experience by maintaining chat context and improves the codebase's modularity and testability.

Highlights

  • Feature Implementation: Implemented session persistence for the CLI chat history, enabling user and Gemini messages to be saved to and loaded from a .gemini/session.json file across application sessions.
  • Code Refactoring: Extracted the session persistence logic from the main App.tsx component into a new, dedicated useSessionPersistence React hook. This significantly improves code organization, reusability, and separation of concerns.
  • Test Coverage: Added comprehensive unit tests for the new useSessionPersistence hook. These tests thoroughly validate the hook's behavior, including history loading, saving, and proper handling of process exit events, by mocking file system operations.
  • Configuration: Introduced a new session.persistence setting within the application's configuration, allowing users to easily enable or disable the chat history persistence feature.
  • Type System Enhancement: Added a new MessageType.TOOL_GROUP enum member to the MessageType enum in types.ts, expanding the types of messages that can be represented.
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 in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

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 issue 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 is currently in preview and 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 to provide feedback.

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
Copy Markdown
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 refactors session persistence logic into a dedicated useSessionPersistence hook, improving modularity and testability. A performance issue was identified where synchronous file I/O is used for loading session history, which could block the UI on startup. A suggestion to switch to asynchronous I/O has been provided.

Comment thread packages/cli/src/ui/hooks/useSessionPersistence.ts Outdated
@JiechengZhao JiechengZhao force-pushed the feat/session-persistence branch from 4cffcb0 to 678de9c Compare July 13, 2025 23:08
mahi424 pushed a commit to ai-assited/gemini-cli-plus that referenced this pull request Jul 14, 2025
mahi424 pushed a commit to ai-assited/gemini-cli-plus that referenced this pull request Jul 14, 2025
@JiechengZhao JiechengZhao force-pushed the feat/session-persistence branch from 678de9c to e12bcb2 Compare July 14, 2025 22:41
@gemini-cli gemini-cli Bot added kind/bug priority/p2 Important but can be addressed in a future release. area/core Issues related to User Interface, OS Support, Core Functionality labels Jul 15, 2025
@JiechengZhao
Copy link
Copy Markdown
Author

/gemini review

Copy link
Copy Markdown
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 refactors the session persistence logic into a new, well-tested useSessionPersistence hook, which improves code organization and maintainability. A high-severity issue was identified regarding data validation when loading the session file. Adding a check to ensure the parsed data is an array will prevent potential runtime crashes from a corrupt session.json file.

Comment thread packages/cli/src/ui/hooks/useSessionPersistence.ts Outdated
@JiechengZhao JiechengZhao force-pushed the feat/session-persistence branch from 5342f01 to 1f64dc4 Compare July 15, 2025 06:52
@JiechengZhao
Copy link
Copy Markdown
Author

/gemini review

Copy link
Copy Markdown
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 successfully refactors session persistence logic into a dedicated useSessionPersistence hook, improving modularity. The accompanying tests are thorough.

My review identifies a critical issue where history items loaded from the session are missing required id properties, which would cause rendering problems. I've also found a typing issue in the test data. I've provided suggestions to fix both issues.

Comment thread packages/cli/src/ui/hooks/useSessionPersistence.ts Outdated
Comment thread packages/cli/src/ui/hooks/useSessionPersistence.test.ts Outdated
@JiechengZhao JiechengZhao force-pushed the feat/session-persistence branch from 1f64dc4 to 9582dc1 Compare July 15, 2025 08:00
@JiechengZhao
Copy link
Copy Markdown
Author

/gemini review

Copy link
Copy Markdown
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 introduces session persistence for the CLI chat history by refactoring the session persistence logic into a new useSessionPersistence hook and adding comprehensive unit tests. The review focuses on enhancing the robustness of the new hook by hardening the session loading logic against malformed data and preventing a potential race condition in ID generation.

Comment thread packages/cli/src/ui/hooks/useSessionPersistence.ts Outdated
@JiechengZhao JiechengZhao force-pushed the feat/session-persistence branch from 9582dc1 to 465bea0 Compare July 15, 2025 22:15
@JiechengZhao
Copy link
Copy Markdown
Author

/gemini review

Copy link
Copy Markdown
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 refactors session persistence logic into a dedicated hook, improving code organization and testability. Comprehensive tests cover many edge cases. A high-severity issue was identified in the hook's handling of non-array session data, potentially causing inconsistent behavior and confusing error messages. The provided feedback addresses this issue.

Comment thread packages/cli/src/ui/hooks/useSessionPersistence.ts Outdated
@JiechengZhao JiechengZhao force-pushed the feat/session-persistence branch from 465bea0 to 88bb400 Compare July 15, 2025 22:27
@JiechengZhao
Copy link
Copy Markdown
Author

/gemini review

Copy link
Copy Markdown
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 refactors session persistence logic into a dedicated useSessionPersistence hook, improving modularity and separation of concerns. A potential performance issue was identified in the new hook where the exit event handler is re-registered on every history change. A code suggestion was provided to refactor this using a useRef to hold the history, which is a more standard and performant pattern for this use case.

Comment thread packages/cli/src/ui/hooks/useSessionPersistence.ts Outdated
@JiechengZhao
Copy link
Copy Markdown
Author

/gemini review

Copy link
Copy Markdown
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 effectively refactors the session persistence logic into a dedicated useSessionPersistence hook, which is a great improvement for code organization and testability. The new hook is well-implemented and comes with a comprehensive set of unit tests that cover various success and failure scenarios.

I have one high-severity suggestion for the useSessionPersistence.ts file to improve its robustness by ensuring all file system operations that can throw errors within the exit handler are properly wrapped in a try...catch block. This will prevent unhandled exceptions from crashing the process during shutdown.

Overall, this is a solid contribution that improves the maintainability of the codebase.

Comment thread packages/cli/src/ui/hooks/useSessionPersistence.ts Outdated
@JiechengZhao JiechengZhao force-pushed the feat/session-persistence branch from bc5a352 to e76acfa Compare July 16, 2025 06:54
@JiechengZhao
Copy link
Copy Markdown
Author

/gemini review

@JiechengZhao JiechengZhao force-pushed the feat/session-persistence branch from 8d972b2 to baf2eee Compare July 22, 2025 05:42
@JiechengZhao
Copy link
Copy Markdown
Author

/gemini review

Copy link
Copy Markdown
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 does a great job of refactoring the session persistence logic into a dedicated and well-tested useSessionPersistence hook. The separation of concerns is a significant improvement for maintainability.

My main feedback is a critical security and usability issue regarding the storage location of the session file. It's currently being saved in the current working directory, which could lead to data exposure and a fragmented user experience. I've provided a detailed comment with a suggested fix to store the session file in the user's home directory instead.

Once that is addressed, this will be a solid contribution.

Comment thread packages/cli/src/ui/hooks/useSessionPersistence.ts Outdated
JiechengZhao and others added 2 commits July 22, 2025 17:14
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
@JiechengZhao
Copy link
Copy Markdown
Author

/gemini review

Copy link
Copy Markdown
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

The pull request refactors session persistence logic into a dedicated hook, improving code organization. A critical issue exists in the test suite where the file path validation is incorrect, leading to unreliable tests. The test suite needs to be updated to ensure the persistence logic is properly covered.

Comment on lines +96 to +97
const sessionPath = path.join(tempDir, '.gemini', 'session.json');
expect(fs.existsSync(sessionPath)).toBe(true);
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.

critical

The test logic uses tempDir to construct the session file path, but the useSessionPersistence hook uses USER_SETTINGS_DIR (based on os.homedir()). This discrepancy means the test isn't validating the correct file location. Update the test to use path.join(os.homedir(), '.gemini', 'session.json') to match the hook's behavior.

Suggested change
const sessionPath = path.join(tempDir, '.gemini', 'session.json');
expect(fs.existsSync(sessionPath)).toBe(true);
const sessionPath = path.join(os.homedir(), '.gemini', 'session.json');
expect(fs.existsSync(sessionPath)).toBe(true);

@JiechengZhao
Copy link
Copy Markdown
Author

/gemini review

Copy link
Copy Markdown
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 refactors the session persistence logic into a dedicated useSessionPersistence hook, improving code organization and testability. However, the inline onLoadComplete callback in App.tsx causes repeated session history loading, leading to data duplication. Memoizing the callback with useCallback is recommended to prevent this issue.

Comment on lines +119 to +124
useSessionPersistence({
sessionPersistence,
history,
loadHistory,
onLoadComplete: () => setSessionLoaded(true),
});
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.

critical

The onLoadComplete callback passed to useSessionPersistence is created inline, which means a new function instance is generated on every render of the App component.

The useSessionPersistence hook includes this callback in a useEffect dependency array. Consequently, the effect that loads the session history from disk re-runs on every render of App. This leads to the session history being repeatedly loaded and prepended to the state, causing severe data duplication in the chat history.

To fix this, the onLoadComplete callback must be memoized with useCallback to ensure it has a stable reference across re-renders.

  const [sessionLoaded, setSessionLoaded] = useState(false);
  const onLoadComplete = useCallback(() => setSessionLoaded(true), []);
  useSessionPersistence({
    sessionPersistence,
    history,
    loadHistory,
    onLoadComplete,
  });

@JiechengZhao
Copy link
Copy Markdown
Author

/gemini review

Copy link
Copy Markdown
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 refactors session persistence logic into a dedicated useSessionPersistence hook, improving modularity and separation of concerns. The new hook is well-implemented with robust error handling and includes a comprehensive set of integration tests. The changes in App.tsx to consume this hook are clean and correct.

@jacob314
Copy link
Copy Markdown
Contributor

Thanks for the contribution. I'm sorry we did not review it in a timely manner. Closing as duplicate work related has started to land in the small pr's linked off of #4401 has landed.
Please do reach out if you are interested in making any other contributions to Gemini CLI and I would like to personally ensure you get more timely PR reviews next time. In particular I am the right reviewer for generally most issues under
#5303

Thanks,
Jacob

@jacob314 jacob314 closed this Aug 22, 2025
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 priority/p2 Important but can be addressed in a future release.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: Implement session persistence for CLI chat history

3 participants