feat(cli): add /new command to start fresh sessions without overwriting existing history#20431
Conversation
…SuvanshTembe/gemini-cli into test/auto-edit-read-permissions
Summary of ChangesHello @SuvanshTembe, 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 significantly enhances session management within the CLI by introducing a dedicated Highlights
Changelog
Activity
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.
Code Review
This pull request introduces a /new command to start a fresh session, which is a great usability improvement. The implementation correctly separates core logic from the UI by introducing a performNewSession generator in the core package. However, there's a significant architectural issue in the CLI package where the session creation logic is duplicated and split between newCommand.ts and useSlashCommandProcessor.ts. My review focuses on consolidating this logic into the useSlashCommandProcessor hook to improve maintainability and ensure correctness, aligning with the rule to avoid duplicating subcommand routing logic. This involves refactoring newCommand to delegate handling to the processor and completing the implementation in the processor's clear_session handler to ensure all related logic is centralized.
| action: async ( | ||
| context: CommandContext, | ||
| _args: string, | ||
| ): Promise<void | SlashCommandActionReturn> => { | ||
| const actionStream = performNewSession(); | ||
|
|
||
| for await (const action of actionStream) { | ||
| if (action.type === 'message') { | ||
| context.ui.addItem( | ||
| { | ||
| type: action.messageType, | ||
| text: action.content, | ||
| }, | ||
| Date.now(), | ||
| ); | ||
| } else if (action.type === 'clear_session') { | ||
| const geminiClient = context.services.config?.getGeminiClient(); | ||
| const config = context.services.config; | ||
| const chatRecordingService = context.services.config | ||
| ?.getGeminiClient() | ||
| ?.getChat() | ||
| .getChatRecordingService(); | ||
|
|
||
| if (geminiClient) { | ||
| await geminiClient.resetChat(); | ||
| } | ||
|
|
||
| // Reset user steering hints | ||
| config?.userHintService.clear(); | ||
|
|
||
| // Start a new conversation recording with a new session ID | ||
| if (config && chatRecordingService) { | ||
| const newSessionId = randomUUID(); | ||
| config.setSessionId(newSessionId); | ||
| chatRecordingService.initialize(); | ||
| } | ||
|
|
||
| context.ui.clear(); | ||
| } | ||
| } | ||
| }, |
There was a problem hiding this comment.
The logic for creating a new session is implemented directly within this command's action. However, a handler for the clear_session action has also been added to useSlashCommandProcessor.ts, leading to duplicated and split logic. This is a maintainability concern, as both places would need to be kept in sync.
To centralize UI and state update logic, this command should delegate handling to the useSlashCommandProcessor hook. Please refactor this action to return the clear_session action object yielded by performNewSession(). The processor will then execute the complete session creation logic.
action: async (
context: CommandContext,
_args: string,
): Promise<void | SlashCommandActionReturn> => {
const actionStream = performNewSession();
let lastAction: SlashCommandActionReturn | undefined;
for await (const action of actionStream) {
if (action.type === 'message') {
context.ui.addItem(
{
type: action.messageType,
text: action.content,
},
Date.now(),
);
} else {
lastAction = action;
}
}
return lastAction;
},References
- Avoid duplicating subcommand routing logic within a parent command's action if a higher-level CLI router is already responsible for it. The parent command's action should only contain the default behavior.
| case 'clear_session': { | ||
| const newSessionId = createSessionId(); | ||
| config?.setSessionId(newSessionId); | ||
| await config?.getGeminiClient()?.resetChat(); | ||
| fullCommandContext.ui.clear(); | ||
| setSessionShellAllowlist(new Set()); | ||
| setPendingItem(null); | ||
| return { type: 'handled' }; | ||
| } |
There was a problem hiding this comment.
This handler for clear_session is incomplete. It's missing calls to userHintService.clear() and chatRecordingService.initialize(), which are necessary to fully reset the session state and create a new session file on disk.
As this is the centralized place for handling session creation, all related logic should be consolidated here. This ensures that starting a new session is handled consistently and correctly.
case 'clear_session': {
const newSessionId = createSessionId();
config?.setSessionId(newSessionId);
await config?.getGeminiClient()?.resetChat();
// Reset user steering hints for the new session.
config?.userHintService.clear();
// Re-initialize the recording service to create a new session file.
config
?.getGeminiClient()
?.getChat()
.getChatRecordingService()
?.initialize();
fullCommandContext.ui.clear();
setSessionShellAllowlist(new Set());
setPendingItem(null);
return { type: 'handled' };
}References
- Avoid duplicating subcommand routing logic within a parent command's action if a higher-level CLI router is already responsible for it. This rule supports centralizing all related logic within the designated router to ensure completeness and consistency.
|
This seems like a duplicate of #16848 Going to see if the original author of that PR is open to continuing to work on this. |
|
Really appreciate the contribution @SuvanshTembe 👏 Friendly reminder to do a quick search for open issues and PRs ahead of starting work so that it saves you from working on something that someone has already worked or started on 😄 |
|
@jackwotherspoon Understood. I'll check first from next time. |
Summary
This PR introduces a new /new slash command that allows users to start a completely fresh session directly within the Gemini CLI. Currently, users must manually run /save followed by /clear, or restart the CLI, to avoid overwriting their existing session. The new command simplifies session management by generating a new session UUID while preserving the previous session for later use via /resume.
Details
Related Issues
Closes #20428
How to Validate
/new
Expected:
A new session starts.
Previous session remains available via /resume.
Edge cases tested:
Running /new multiple times consecutively
Switching between /new and /resume
Starting a new session after /clear
Pre-Merge Checklist
Screenshots
Before(session one):



After creating a new session with /new (session two):
Result (Both sessions are saved):