feat(sessions): use 1-line generated session summary to describe sessions (#14467)

This commit is contained in:
Jack Wotherspoon
2025-12-05 12:20:15 -05:00
committed by GitHub
parent 8341256d1e
commit 616d6f6667
10 changed files with 1639 additions and 4 deletions

View File

@@ -63,6 +63,7 @@ import {
SessionEndReason,
fireSessionStartHook,
fireSessionEndHook,
generateAndSaveSummary,
} from '@google/gemini-cli-core';
import { validateAuthMethod } from '../config/auth.js';
import process from 'node:process';
@@ -312,6 +313,7 @@ export const AppContainer = (props: AppContainerProps) => {
}
})();
registerCleanup(async () => {
await generateAndSaveSummary(config);
// Turn off mouse scroll.
disableMouseEvents();
const ideClient = await IdeClient.getInstance();

View File

@@ -15,6 +15,7 @@ import {
} from '@google/gemini-cli-core';
import * as fs from 'node:fs/promises';
import path from 'node:path';
import { stripUnsafeCharacters } from '../ui/utils/textUtils.js';
/**
* Constant for the resume "latest" identifier.
@@ -60,6 +61,8 @@ export interface SessionInfo {
isCurrentSession: boolean;
/** Display index in the list */
index: number;
/** AI-generated summary of the session (if available) */
summary?: string;
/** Full concatenated content (only loaded when needed for search) */
fullContent?: string;
/** Processed messages with normalized roles (only loaded when needed) */
@@ -259,10 +262,13 @@ export const getAllSessionFiles = async (
startTime: content.startTime,
lastUpdated: content.lastUpdated,
messageCount: content.messages.length,
displayName: firstUserMessage,
displayName: content.summary
? stripUnsafeCharacters(content.summary)
: firstUserMessage,
firstUserMessage,
isCurrentSession,
index: 0, // Will be set after sorting valid sessions
summary: content.summary,
fullContent,
messages,
};

View File

@@ -290,6 +290,40 @@ describe('listSessions', () => {
expect.stringContaining(', current)'),
);
});
it('should display summary as title when available instead of first user message', async () => {
// Arrange
const now = new Date('2025-01-20T12:00:00.000Z');
const mockSessions: SessionInfo[] = [
{
id: 'session-with-summary',
file: 'session-file',
fileName: 'session-file.json',
startTime: now.toISOString(),
lastUpdated: now.toISOString(),
messageCount: 10,
displayName: 'Add dark mode to the app', // Summary
firstUserMessage:
'How do I add dark mode to my React application with CSS variables?',
isCurrentSession: false,
index: 1,
summary: 'Add dark mode to the app',
},
];
mockListSessions.mockResolvedValue(mockSessions);
// Act
await listSessions(mockConfig);
// Assert: Should show the summary (displayName), not the first user message
expect(consoleLogSpy).toHaveBeenCalledWith(
expect.stringContaining('1. Add dark mode to the app'),
);
expect(consoleLogSpy).not.toHaveBeenCalledWith(
expect.stringContaining('How do I add dark mode to my React application'),
);
});
});
describe('deleteSession', () => {

View File

@@ -31,9 +31,9 @@ export async function listSessions(config: Config): Promise<void> {
const current = session.isCurrentSession ? ', current' : '';
const time = formatRelativeTime(session.lastUpdated);
const title =
session.firstUserMessage.length > 100
? session.firstUserMessage.slice(0, 97) + '...'
: session.firstUserMessage;
session.displayName.length > 100
? session.displayName.slice(0, 97) + '...'
: session.displayName;
console.log(
` ${index + 1}. ${title} (${time}${current}) [${session.id}]`,
);