mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-03-03 21:17:50 +00:00
Fix session processing state leaking across session switches
Root cause: - Processing ownership was derived from UI view state in ChatInterface. - While switching sessions, an in-flight isLoading=true could stamp the newly selected session as processing, even if a different session was actually running. - session-status handling only promoted isProcessing=true and did not clear stale processing state on isProcessing=false, which could leave sessions blocked. Changes: - ChatInterface: removed implicit processing propagation effect that called onSessionProcessing(selectedSession?.id || currentSessionId) when isLoading was true. This decouples processing ownership from transient view/session transitions. - useChatComposerState: added onSessionProcessing callback usage and explicitly marks processing at submit time for the concrete effectiveSessionId (non-temporary IDs only). This ties processing to the session that actually started work. - useChatRealtimeHandlers: expanded session-status handling to support both states. - isProcessing=true: mark session as processing; set loading/abort only when it is the currently viewed session. - isProcessing=false: clear active+processing markers and clear loading indicators for the current session view. Behavioral outcome: - Running session A no longer blocks session B after navigation. - Users can work in multiple sessions concurrently, and processing badges/loading state stay session-scoped. Verification: - npm run typecheck - npm run build
This commit is contained in:
@@ -47,6 +47,7 @@ interface UseChatComposerStateArgs {
|
||||
sendMessage: (message: unknown) => void;
|
||||
sendByCtrlEnter?: boolean;
|
||||
onSessionActive?: (sessionId?: string | null) => void;
|
||||
onSessionProcessing?: (sessionId?: string | null) => void;
|
||||
onInputFocusChange?: (focused: boolean) => void;
|
||||
onFileOpen?: (filePath: string, diffInfo?: unknown) => void;
|
||||
onShowSettings?: () => void;
|
||||
@@ -98,6 +99,7 @@ export function useChatComposerState({
|
||||
sendMessage,
|
||||
sendByCtrlEnter,
|
||||
onSessionActive,
|
||||
onSessionProcessing,
|
||||
onInputFocusChange,
|
||||
onFileOpen,
|
||||
onShowSettings,
|
||||
@@ -569,6 +571,9 @@ export function useChatComposerState({
|
||||
pendingViewSessionRef.current = { sessionId: null, startedAt: Date.now() };
|
||||
}
|
||||
onSessionActive?.(sessionToActivate);
|
||||
if (effectiveSessionId && !isTemporarySessionId(effectiveSessionId)) {
|
||||
onSessionProcessing?.(effectiveSessionId);
|
||||
}
|
||||
|
||||
const getToolsSettings = () => {
|
||||
try {
|
||||
@@ -666,6 +671,7 @@ export function useChatComposerState({
|
||||
executeCommand,
|
||||
isLoading,
|
||||
onSessionActive,
|
||||
onSessionProcessing,
|
||||
pendingViewSessionRef,
|
||||
permissionMode,
|
||||
provider,
|
||||
|
||||
@@ -956,12 +956,26 @@ export function useChatRealtimeHandlers({
|
||||
|
||||
case 'session-status': {
|
||||
const statusSessionId = latestMessage.sessionId;
|
||||
if (!statusSessionId) {
|
||||
break;
|
||||
}
|
||||
|
||||
const isCurrentSession =
|
||||
statusSessionId === currentSessionId || (selectedSession && statusSessionId === selectedSession.id);
|
||||
if (isCurrentSession && latestMessage.isProcessing) {
|
||||
setIsLoading(true);
|
||||
setCanAbortSession(true);
|
||||
|
||||
if (latestMessage.isProcessing) {
|
||||
onSessionProcessing?.(statusSessionId);
|
||||
if (isCurrentSession) {
|
||||
setIsLoading(true);
|
||||
setCanAbortSession(true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
onSessionInactive?.(statusSessionId);
|
||||
onSessionNotProcessing?.(statusSessionId);
|
||||
if (isCurrentSession) {
|
||||
clearLoadingIndicators();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -180,6 +180,7 @@ function ChatInterface({
|
||||
sendMessage,
|
||||
sendByCtrlEnter,
|
||||
onSessionActive,
|
||||
onSessionProcessing,
|
||||
onInputFocusChange,
|
||||
onFileOpen,
|
||||
onShowSettings,
|
||||
@@ -238,13 +239,6 @@ function ChatInterface({
|
||||
};
|
||||
}, [canAbortSession, handleAbortSession, isLoading]);
|
||||
|
||||
useEffect(() => {
|
||||
const processingSessionId = selectedSession?.id || currentSessionId;
|
||||
if (processingSessionId && isLoading && onSessionProcessing) {
|
||||
onSessionProcessing(processingSessionId);
|
||||
}
|
||||
}, [currentSessionId, isLoading, onSessionProcessing, selectedSession?.id]);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
resetStreamingState();
|
||||
|
||||
Reference in New Issue
Block a user