unify on one DEFAULT_CHAT_TITLE

This commit is contained in:
Zane Staggs
2025-12-01 15:57:46 -08:00
parent f2f8e9e13e
commit 8c20f96188
7 changed files with 47 additions and 43 deletions
+1 -1
View File
@@ -142,7 +142,7 @@ async fn start_agent(
}
let counter = state.session_counter.fetch_add(1, Ordering::SeqCst) + 1;
let name = format!("New chat {}", counter);
let name = format!("New Chat {}", counter);
let mut session =
SessionManager::create_session(PathBuf::from(&working_dir), name, SessionType::User)
+2 -2
View File
@@ -26,7 +26,7 @@ import SharedSessionView from './components/sessions/SharedSessionView';
import SchedulesView from './components/schedule/SchedulesView';
import ProviderSettings from './components/settings/providers/ProviderSettingsPage';
import { AppLayout } from './components/Layout/AppLayout';
import { ChatProvider } from './contexts/ChatContext';
import { ChatProvider, DEFAULT_CHAT_TITLE } from './contexts/ChatContext';
import LauncherView from './components/LauncherView';
import 'react-toastify/dist/ReactToastify.css';
@@ -323,7 +323,7 @@ export function AppInner() {
const [chat, setChat] = useState<ChatType>({
sessionId: '',
name: 'Pair Chat',
name: DEFAULT_CHAT_TITLE,
messages: [],
messageHistoryIndex: 0,
recipe: null,
@@ -20,6 +20,7 @@ import { resumeSession, startNewSession } from '../../sessions';
import { useNavigation } from '../../hooks/useNavigation';
import { SessionIndicators } from '../SessionIndicators';
import { useSessionStatusContext } from '../../contexts/SessionStatusContext';
import { isDefaultSessionName } from '../../sessions';
interface SidebarProps {
onSelectSession: (sessionId: string) => void;
@@ -91,6 +92,9 @@ const SessionList = React.memo<{
const isStreaming = status?.streamState === 'streaming';
const hasError = status?.streamState === 'error';
const hasUnread = status?.hasUnreadActivity ?? false;
const displayName = isDefaultSessionName(session.name)
? DEFAULT_CHAT_TITLE
: session.name;
return (
<button
@@ -101,9 +105,9 @@ const SessionList = React.memo<{
? 'bg-background-medium text-text-default'
: 'text-text-muted hover:bg-background-medium/50 hover:text-text-default'
}`}
title={session.name}
title={displayName}
>
<span className="flex-1 truncate min-w-0 block">{session.name}</span>
<span className="flex-1 truncate min-w-0 block">{displayName}</span>
<SessionIndicators
isStreaming={isStreaming}
hasUnread={hasUnread}
@@ -175,13 +179,7 @@ const AppSidebar: React.FC<SidebarProps> = ({ currentPath }) => {
const sessions = response.data.sessions.slice(0, 10);
setRecentSessions(sessions);
const hasSessionWithDefaultName = sessions.some(
(s) =>
s.name === DEFAULT_CHAT_TITLE ||
s.name === 'Pair Chat' ||
s.name === 'New Chat' ||
s.name.startsWith('New chat ')
);
const hasSessionWithDefaultName = sessions.some((s) => isDefaultSessionName(s.name));
if (hasSessionWithDefaultName) {
window.dispatchEvent(new CustomEvent('session-needs-name-update'));
@@ -219,13 +217,7 @@ const AppSidebar: React.FC<SidebarProps> = ({ currentPath }) => {
const sessions = response.data.sessions.slice(0, 10);
setRecentSessions(sessions);
const sessionWithDefaultName = sessions.find(
(s) =>
s.name === DEFAULT_CHAT_TITLE ||
s.name === 'Pair Chat' ||
s.name === 'New Chat' ||
s.name.startsWith('New chat ')
);
const sessionWithDefaultName = sessions.find((s) => isDefaultSessionName(s.name));
const shouldContinue = pollCount < maxPolls && (sessionWithDefaultName || pollCount < 5);
@@ -2,6 +2,8 @@ import React from 'react';
import { Card } from '../ui/card';
import { formatDate } from '../../utils/date';
import { Session } from '../../api';
import { isDefaultSessionName } from '../../sessions';
import { DEFAULT_CHAT_TITLE } from '../../contexts/ChatContext';
interface SessionItemProps {
session: Session;
@@ -9,10 +11,12 @@ interface SessionItemProps {
}
const SessionItem: React.FC<SessionItemProps> = ({ session, extraActions }) => {
const displayName = isDefaultSessionName(session.name) ? DEFAULT_CHAT_TITLE : session.name;
return (
<Card className="p-4 mb-2 hover:bg-accent/50 cursor-pointer flex justify-between items-center">
<div>
<div className="font-medium">{session.name}</div>
<div className="font-medium">{displayName}</div>
<div className="text-sm text-muted-foreground">
{formatDate(session.updated_at)} • {session.message_count} messages
</div>
@@ -30,6 +30,8 @@ import {
Session,
updateSessionName,
} from '../../api';
import { isDefaultSessionName } from '../../sessions';
import { DEFAULT_CHAT_TITLE } from '../../contexts/ChatContext';
interface EditSessionModalProps {
session: Session | null;
@@ -547,6 +549,8 @@ const SessionListView: React.FC<SessionListViewProps> = React.memo(
[onOpenInNewWindow, session]
);
const displayName = isDefaultSessionName(session.name) ? DEFAULT_CHAT_TITLE : session.name;
return (
<Card
onClick={handleCardClick}
@@ -554,7 +558,7 @@ const SessionListView: React.FC<SessionListViewProps> = React.memo(
ref={(el) => setSessionRefs(session.id, el)}
>
<div className="flex items-start justify-between gap-2 mb-1">
<h3 className="text-base break-words line-clamp-2 flex-1 min-w-0">{session.name}</h3>
<h3 className="text-base break-words line-clamp-2 flex-1 min-w-0">{displayName}</h3>
<div className="flex gap-1 opacity-0 group-hover:opacity-100 transition-opacity flex-shrink-0">
<button
onClick={handleOpenInNewWindowClick}
+13 -22
View File
@@ -19,6 +19,7 @@ import {
NotificationEvent,
} from '../types/message';
import { errorMessage } from '../utils/conversionUtils';
import { isDefaultSessionName } from '../sessions';
const resultsCache = new Map<string, { messages: Message[]; session: Session }>();
@@ -187,30 +188,20 @@ export function useChatStream({
// After first AI response, check if session name was updated
// This happens when the AI generates a title for a new conversation
if (session && messagesRef.current.length > 0) {
const isNewSession =
session.name === 'New Chat' ||
session.name === 'Pair Chat' ||
session.name === 'No Session' ||
session.name?.startsWith('New chat ');
if (session && messagesRef.current.length > 0 && isDefaultSessionName(session.name)) {
try {
const { getSession } = await import('../api');
const response = await getSession({
path: { session_id: sessionId },
throwOnError: true,
});
if (isNewSession) {
// Fetch updated session to get the new name
try {
const { getSession } = await import('../api');
const response = await getSession({
path: { session_id: sessionId },
throwOnError: true,
});
if (response.data && response.data.name !== session.name) {
setSession(response.data);
// Dispatch event to update sidebar
window.dispatchEvent(new CustomEvent('session-needs-name-update'));
}
} catch (error) {
console.error('Failed to fetch updated session:', error);
if (response.data && response.data.name !== session.name) {
setSession(response.data);
window.dispatchEvent(new CustomEvent('session-needs-name-update'));
}
} catch (error) {
console.error('Failed to fetch updated session:', error);
}
}
+13
View File
@@ -1,5 +1,18 @@
import { Session, startAgent } from './api';
import type { setViewType } from './hooks/useNavigation';
import { DEFAULT_CHAT_TITLE } from './contexts/ChatContext';
/**
* Check if a session name is a default/temporary name that should be updated
* @param name - The session name to check
* @returns true if the name is a default/temporary name
*/
export function isDefaultSessionName(name: string | undefined | null): boolean {
if (!name) return false;
// Check if it's exactly the default title or starts with it (for numbered versions)
return name === DEFAULT_CHAT_TITLE || name.startsWith(DEFAULT_CHAT_TITLE);
}
export function resumeSession(session: Session, setView: setViewType) {
const eventDetail = {