diff --git a/src/components/app/AppContent.tsx b/src/components/app/AppContent.tsx index 4dd6979a..1ba41b95 100644 --- a/src/components/app/AppContent.tsx +++ b/src/components/app/AppContent.tsx @@ -34,7 +34,6 @@ function AppContentInner() { markSessionAsInactive, markSessionAsProcessing, markSessionAsNotProcessing, - replaceTemporarySession, } = useSessionProtection(); const { @@ -191,7 +190,6 @@ function AppContentInner() { onSessionProcessing={markSessionAsProcessing} onSessionNotProcessing={markSessionAsNotProcessing} processingSessions={processingSessions} - onReplaceTemporarySession={replaceTemporarySession} onNavigateToSession={(targetSessionId: string, options) => navigate(`/session/${targetSessionId}`, { replace: Boolean(options?.replace) }) } diff --git a/src/components/chat/hooks/useChatComposerState.ts b/src/components/chat/hooks/useChatComposerState.ts index c53cd01d..bbf188b9 100644 --- a/src/components/chat/hooks/useChatComposerState.ts +++ b/src/components/chat/hooks/useChatComposerState.ts @@ -10,6 +10,7 @@ import type { TouchEvent, } from 'react'; import { useDropzone } from 'react-dropzone'; + import { authenticatedFetch } from '../../../utils/api'; import { thinkingModes } from '../constants/thinkingModes'; import { grantClaudeToolPermission } from '../utils/chatPermissions'; @@ -21,6 +22,7 @@ import type { } from '../types/types'; import type { Project, ProjectSession, LLMProvider } from '../../../types/app'; import { escapeRegExp } from '../utils/chatFormatting'; + import { useFileMentions } from './useFileMentions'; import { type SlashCommand, useSlashCommands } from './useSlashCommands'; @@ -80,9 +82,6 @@ const createFakeSubmitEvent = () => { return { preventDefault: () => undefined } as unknown as FormEvent; }; -const isTemporarySessionId = (sessionId: string | null | undefined) => - Boolean(sessionId && sessionId.startsWith('new-session-')); - const getNotificationSessionSummary = ( selectedSession: ProjectSession | null, fallbackInput: string, @@ -533,7 +532,12 @@ export function useChatComposerState({ const effectiveSessionId = currentSessionId || selectedSession?.id || sessionStorage.getItem('cursorSessionId'); - const sessionToActivate = effectiveSessionId || `new-session-${Date.now()}`; + + console.log('Submitting message', { + content: messageContent, + sessionId: effectiveSessionId, + images: uploadedImages, + }); const userMessage: ChatMessage = { type: 'user', @@ -559,10 +563,12 @@ export function useChatComposerState({ // Reset stale pending IDs from previous interrupted runs before creating a new one. sessionStorage.removeItem('pendingSessionId'); } + // For new sessions we intentionally keep this as `null` until the backend + // emits `session_created` with the canonical provider session id. pendingViewSessionRef.current = { sessionId: null, startedAt: Date.now() }; } - onSessionActive?.(sessionToActivate); - if (effectiveSessionId && !isTemporarySessionId(effectiveSessionId)) { + if (effectiveSessionId) { + onSessionActive?.(effectiveSessionId); onSessionProcessing?.(effectiveSessionId); } @@ -868,7 +874,7 @@ export function useChatComposerState({ ]; const targetSessionId = - candidateSessionIds.find((sessionId) => Boolean(sessionId) && !isTemporarySessionId(sessionId)) || null; + candidateSessionIds.find((sessionId) => Boolean(sessionId)) || null; if (!targetSessionId) { console.warn('Abort requested but no concrete session ID is available yet.'); diff --git a/src/components/chat/hooks/useChatRealtimeHandlers.ts b/src/components/chat/hooks/useChatRealtimeHandlers.ts index 4ae861db..86c85469 100644 --- a/src/components/chat/hooks/useChatRealtimeHandlers.ts +++ b/src/components/chat/hooks/useChatRealtimeHandlers.ts @@ -65,7 +65,6 @@ interface UseChatRealtimeHandlersArgs { onSessionInactive?: (sessionId?: string | null) => void; onSessionProcessing?: (sessionId?: string | null) => void; onSessionNotProcessing?: (sessionId?: string | null) => void; - onReplaceTemporarySession?: (sessionId?: string | null) => void; onNavigateToSession?: (sessionId: string, options?: SessionNavigationOptions) => void; onWebSocketReconnect?: () => void; sessionStore: SessionStore; @@ -92,7 +91,6 @@ export function useChatRealtimeHandlers({ onSessionInactive, onSessionProcessing, onSessionNotProcessing, - onReplaceTemporarySession, onNavigateToSession, onWebSocketReconnect, sessionStore, @@ -232,7 +230,9 @@ export function useChatRealtimeHandlers({ const newSessionId = msg.newSessionId; if (!newSessionId) break; - if (!currentSessionId || currentSessionId.startsWith('new-session-')) { + // We no longer synthesize client-side placeholder IDs. Until the provider + // announces `session_created`, the active id is expected to be null. + if (!currentSessionId) { console.log('Session created with ID:', newSessionId); console.log('Existing session ID:', currentSessionId); sessionStorage.setItem('pendingSessionId', newSessionId); @@ -240,7 +240,6 @@ export function useChatRealtimeHandlers({ pendingViewSessionRef.current.sessionId = newSessionId; } setCurrentSessionId(newSessionId); - onReplaceTemporarySession?.(newSessionId); setPendingPermissionRequests((prev) => prev.map((r) => (r.sessionId ? r : { ...r, sessionId: newSessionId })), ); @@ -402,7 +401,6 @@ export function useChatRealtimeHandlers({ onSessionInactive, onSessionProcessing, onSessionNotProcessing, - onReplaceTemporarySession, onNavigateToSession, onWebSocketReconnect, sessionStore, diff --git a/src/components/chat/hooks/useChatSessionState.ts b/src/components/chat/hooks/useChatSessionState.ts index 6bff4a88..451c3482 100644 --- a/src/components/chat/hooks/useChatSessionState.ts +++ b/src/components/chat/hooks/useChatSessionState.ts @@ -628,7 +628,7 @@ export function useChatSessionState({ // Token usage fetch for Claude useEffect(() => { - if (!selectedProject || !selectedSession?.id || selectedSession.id.startsWith('new-session-')) { + if (!selectedProject || !selectedSession?.id) { setTokenBudget(null); return; } diff --git a/src/components/chat/types/types.ts b/src/components/chat/types/types.ts index 81bd5a5b..f8d492e5 100644 --- a/src/components/chat/types/types.ts +++ b/src/components/chat/types/types.ts @@ -108,7 +108,6 @@ export interface ChatInterfaceProps { onSessionProcessing?: (sessionId?: string | null) => void; onSessionNotProcessing?: (sessionId?: string | null) => void; processingSessions?: Set; - onReplaceTemporarySession?: (sessionId?: string | null) => void; onNavigateToSession?: (targetSessionId: string, options?: SessionNavigationOptions) => void; onShowSettings?: () => void; autoExpandTools?: boolean; diff --git a/src/components/chat/view/ChatInterface.tsx b/src/components/chat/view/ChatInterface.tsx index 46e95abd..2bff948d 100644 --- a/src/components/chat/view/ChatInterface.tsx +++ b/src/components/chat/view/ChatInterface.tsx @@ -34,7 +34,6 @@ function ChatInterface({ onSessionProcessing, onSessionNotProcessing, processingSessions, - onReplaceTemporarySession, onNavigateToSession, onShowSettings, autoExpandTools, @@ -237,7 +236,6 @@ function ChatInterface({ onSessionInactive, onSessionProcessing, onSessionNotProcessing, - onReplaceTemporarySession, onNavigateToSession, onWebSocketReconnect: handleWebSocketReconnect, sessionStore, diff --git a/src/components/main-content/types/types.ts b/src/components/main-content/types/types.ts index d090852d..68b03b29 100644 --- a/src/components/main-content/types/types.ts +++ b/src/components/main-content/types/types.ts @@ -51,7 +51,6 @@ export type MainContentProps = { onSessionProcessing: SessionLifecycleHandler; onSessionNotProcessing: SessionLifecycleHandler; processingSessions: Set; - onReplaceTemporarySession: SessionLifecycleHandler; onNavigateToSession: (targetSessionId: string, options?: SessionNavigationOptions) => void; onShowSettings: () => void; externalMessageUpdate: number; diff --git a/src/components/main-content/view/MainContent.tsx b/src/components/main-content/view/MainContent.tsx index 1a9c7349..f0a29a70 100644 --- a/src/components/main-content/view/MainContent.tsx +++ b/src/components/main-content/view/MainContent.tsx @@ -47,7 +47,6 @@ function MainContent({ onSessionProcessing, onSessionNotProcessing, processingSessions, - onReplaceTemporarySession, onNavigateToSession, onShowSettings, externalMessageUpdate, @@ -137,7 +136,6 @@ function MainContent({ onSessionProcessing={onSessionProcessing} onSessionNotProcessing={onSessionNotProcessing} processingSessions={processingSessions} - onReplaceTemporarySession={onReplaceTemporarySession} onNavigateToSession={onNavigateToSession} onShowSettings={onShowSettings} autoExpandTools={autoExpandTools} diff --git a/src/hooks/useProjectsState.ts b/src/hooks/useProjectsState.ts index d920fba2..a5397b6b 100644 --- a/src/hooks/useProjectsState.ts +++ b/src/hooks/useProjectsState.ts @@ -435,9 +435,7 @@ export function useProjectsState({ } } - const hasActiveSession = - (selectedSession && activeSessions.has(selectedSession.id)) || - (activeSessions.size > 0 && Array.from(activeSessions).some((id) => id.startsWith('new-session-'))); + const hasActiveSession = Boolean(selectedSession && activeSessions.has(selectedSession.id)); const updatedProjectsWithTaskMaster = mergeTaskMasterCache(projectsMessage.projects, projects); const updatedProjects = mergeExpandedSessionPages(projects, updatedProjectsWithTaskMaster); diff --git a/src/hooks/useSessionProtection.ts b/src/hooks/useSessionProtection.ts index 0c3d1bab..cbdcdda1 100644 --- a/src/hooks/useSessionProtection.ts +++ b/src/hooks/useSessionProtection.ts @@ -44,23 +44,6 @@ export function useSessionProtection() { }); }, []); - const replaceTemporarySession = useCallback((realSessionId?: string | null) => { - if (!realSessionId) { - return; - } - - setActiveSessions((prev) => { - const next = new Set(); - for (const sessionId of prev) { - if (!sessionId.startsWith('new-session-')) { - next.add(sessionId); - } - } - next.add(realSessionId); - return next; - }); - }, []); - return { activeSessions, processingSessions, @@ -68,6 +51,5 @@ export function useSessionProtection() { markSessionAsInactive, markSessionAsProcessing, markSessionAsNotProcessing, - replaceTemporarySession, }; }