From 682d254a9fc066a7f5d262580b570f62d1eb59c6 Mon Sep 17 00:00:00 2001 From: Douwe M Osinga Date: Mon, 20 Jul 2026 10:56:44 +0200 Subject: [PATCH 1/3] fix: sync generated chat title in header --- ui/desktop/src/__tests__/sessions.test.ts | 25 ++++++++++++++++++++++- ui/desktop/src/sessions.ts | 7 ++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/ui/desktop/src/__tests__/sessions.test.ts b/ui/desktop/src/__tests__/sessions.test.ts index 42d564460108..5428b1b3f0be 100644 --- a/ui/desktop/src/__tests__/sessions.test.ts +++ b/ui/desktop/src/__tests__/sessions.test.ts @@ -3,6 +3,7 @@ import { getSessionDisplayName, shouldShowNewChatTitle } from '../sessions'; import { prependUnique } from '../hooks/useNavigationSessions'; import type { SessionListItem } from '../acp/sessions'; import type { Session } from '../types/session'; +import { DEFAULT_CHAT_TITLE } from '../contexts/ChatContext'; // Helper to build a minimal Session object for testing. function makeSession(overrides: Partial = {}): Session { @@ -32,10 +33,23 @@ function makeListItem(overrides: Partial = {}): SessionListItem describe('shouldShowNewChatTitle', () => { it('returns true for an empty session without a user-set name', () => { - const session = makeSession({ message_count: 0, user_set_name: false }); + const session = makeSession({ + name: DEFAULT_CHAT_TITLE, + message_count: 0, + user_set_name: false, + }); expect(shouldShowNewChatTitle(session)).toBe(true); }); + it('returns false when an empty session already has a generated title', () => { + const session = makeSession({ + name: 'Generated title', + message_count: 0, + user_set_name: false, + }); + expect(shouldShowNewChatTitle(session)).toBe(false); + }); + it('returns false when the session has messages', () => { const session = makeSession({ message_count: 3, user_set_name: false }); expect(shouldShowNewChatTitle(session)).toBe(false); @@ -57,6 +71,15 @@ describe('shouldShowNewChatTitle', () => { }); describe('getSessionDisplayName (fix for #8865)', () => { + it('returns a generated title even when message count metadata is stale', () => { + const session = makeSession({ + name: 'Generated title', + user_set_name: false, + message_count: 0, + }); + expect(getSessionDisplayName(session)).toBe('Generated title'); + }); + it('returns the user-set name for a recipe session that has been renamed', () => { const session = makeSession({ name: 'My Renamed Chat', diff --git a/ui/desktop/src/sessions.ts b/ui/desktop/src/sessions.ts index 18ad1e670e32..9df2882ef603 100644 --- a/ui/desktop/src/sessions.ts +++ b/ui/desktop/src/sessions.ts @@ -21,7 +21,12 @@ export function getSessionDisplayName(session: Session): string { } export function shouldShowNewChatTitle(session: Session): boolean { - return !session.user_set_name && session.message_count === 0 && !session.recipe?.title; + return ( + !session.user_set_name && + session.message_count === 0 && + !session.recipe?.title && + session.name === DEFAULT_CHAT_TITLE + ); } export function resumeSession(session: Session, setView: setViewType) { From ec2f03e24a28269aea3906df949ca160e3c2c777 Mon Sep 17 00:00:00 2001 From: Douwe M Osinga Date: Mon, 20 Jul 2026 11:18:50 +0200 Subject: [PATCH 2/3] refactor: trust normalized session titles --- ui/desktop/src/__tests__/sessions.test.ts | 44 ++--------------------- ui/desktop/src/sessions.ts | 13 ------- 2 files changed, 2 insertions(+), 55 deletions(-) diff --git a/ui/desktop/src/__tests__/sessions.test.ts b/ui/desktop/src/__tests__/sessions.test.ts index 5428b1b3f0be..9d80ad0ffa5e 100644 --- a/ui/desktop/src/__tests__/sessions.test.ts +++ b/ui/desktop/src/__tests__/sessions.test.ts @@ -1,9 +1,8 @@ import { describe, it, expect } from 'vitest'; -import { getSessionDisplayName, shouldShowNewChatTitle } from '../sessions'; +import { getSessionDisplayName } from '../sessions'; import { prependUnique } from '../hooks/useNavigationSessions'; import type { SessionListItem } from '../acp/sessions'; import type { Session } from '../types/session'; -import { DEFAULT_CHAT_TITLE } from '../contexts/ChatContext'; // Helper to build a minimal Session object for testing. function makeSession(overrides: Partial = {}): Session { @@ -31,47 +30,8 @@ function makeListItem(overrides: Partial = {}): SessionListItem }; } -describe('shouldShowNewChatTitle', () => { - it('returns true for an empty session without a user-set name', () => { - const session = makeSession({ - name: DEFAULT_CHAT_TITLE, - message_count: 0, - user_set_name: false, - }); - expect(shouldShowNewChatTitle(session)).toBe(true); - }); - - it('returns false when an empty session already has a generated title', () => { - const session = makeSession({ - name: 'Generated title', - message_count: 0, - user_set_name: false, - }); - expect(shouldShowNewChatTitle(session)).toBe(false); - }); - - it('returns false when the session has messages', () => { - const session = makeSession({ message_count: 3, user_set_name: false }); - expect(shouldShowNewChatTitle(session)).toBe(false); - }); - - it('returns false when the user has set a custom name', () => { - const session = makeSession({ message_count: 0, user_set_name: true }); - expect(shouldShowNewChatTitle(session)).toBe(false); - }); - - it('returns false when the session has a recipe', () => { - const session = makeSession({ - message_count: 0, - user_set_name: false, - recipe: { title: 'Recipe', steps: [] } as unknown as Session['recipe'], - }); - expect(shouldShowNewChatTitle(session)).toBe(false); - }); -}); - describe('getSessionDisplayName (fix for #8865)', () => { - it('returns a generated title even when message count metadata is stale', () => { + it('returns the normalized session name even when message count metadata is stale', () => { const session = makeSession({ name: 'Generated title', user_set_name: false, diff --git a/ui/desktop/src/sessions.ts b/ui/desktop/src/sessions.ts index 9df2882ef603..5988b749300a 100644 --- a/ui/desktop/src/sessions.ts +++ b/ui/desktop/src/sessions.ts @@ -1,6 +1,5 @@ import type { Session } from './types/session'; import type { ExtensionConfig } from './types/extensions'; -import { DEFAULT_CHAT_TITLE } from './contexts/ChatContext'; import type { setViewType } from './hooks/useNavigation'; import type { FixedExtensionEntry } from './components/ConfigContext'; import { AppEvents } from './constants/events'; @@ -14,21 +13,9 @@ export function getSessionDisplayName(session: Session): string { if (session.recipe?.title) { return session.recipe.title; } - if (shouldShowNewChatTitle(session)) { - return DEFAULT_CHAT_TITLE; - } return session.name; } -export function shouldShowNewChatTitle(session: Session): boolean { - return ( - !session.user_set_name && - session.message_count === 0 && - !session.recipe?.title && - session.name === DEFAULT_CHAT_TITLE - ); -} - export function resumeSession(session: Session, setView: setViewType) { const eventDetail = { sessionId: session.id, From 2690640346bf21b7d1766c0dfdfe3421ab82c7e0 Mon Sep 17 00:00:00 2001 From: Douwe M Osinga Date: Mon, 20 Jul 2026 11:53:24 +0200 Subject: [PATCH 3/3] refactor: stop synthesizing ACP session titles --- ui/desktop/src/acp/__tests__/sessions.test.ts | 6 ++++++ ui/desktop/src/acp/sessions.ts | 5 ++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/ui/desktop/src/acp/__tests__/sessions.test.ts b/ui/desktop/src/acp/__tests__/sessions.test.ts index c6ca72620be2..c3437c945d9e 100644 --- a/ui/desktop/src/acp/__tests__/sessions.test.ts +++ b/ui/desktop/src/acp/__tests__/sessions.test.ts @@ -33,6 +33,12 @@ describe('ACP sessions', () => { expect(session.session_type).toBe('scheduled'); }); + it('does not synthesize a title when ACP omits one', () => { + const session = sessionInfoToSession(sessionInfo({ title: undefined })); + + expect(session.name).toBe(''); + }); + it('returns session info refreshed after loading the ACP session', async () => { const loadedSessionInfo = sessionInfo({ _meta: { diff --git a/ui/desktop/src/acp/sessions.ts b/ui/desktop/src/acp/sessions.ts index dc1c18321ec4..e03f82b341ac 100644 --- a/ui/desktop/src/acp/sessions.ts +++ b/ui/desktop/src/acp/sessions.ts @@ -7,7 +7,6 @@ import type { } from '@agentclientprotocol/sdk'; import type { GooseExtension, SessionImportSource } from '@aaif/goose-sdk'; import { getAcpClient } from './acpConnection'; -import { DEFAULT_CHAT_TITLE } from '../contexts/ChatContext'; import type { ExtensionLoadResult } from '../types/extensions'; import type { Session } from '../types/session'; import type { Recipe } from '../recipe'; @@ -93,7 +92,7 @@ export function sessionInfoToSession(s: SessionInfo, loadMeta: LoadSessionMeta = return { id: String(s.sessionId), - name: s.title ?? DEFAULT_CHAT_TITLE, + name: s.title ?? '', working_dir: loadMeta.workingDir ?? s.cwd, created_at: createdAt, updated_at: updatedAt, @@ -116,7 +115,7 @@ function sessionInfoToListItem(s: SessionInfo): SessionListItem { const meta = sessionInfoMeta(s); return { id: String(s.sessionId), - name: s.title ?? DEFAULT_CHAT_TITLE, + name: s.title ?? '', workingDir: s.cwd, updatedAt: s.updatedAt ?? '', messageCount: meta.messageCount ?? 0,