From 6e726cdf0d694cedd4176608df71f48270c06345 Mon Sep 17 00:00:00 2001 From: Chris Scott <99081550+chriswritescode-dev@users.noreply.github.com> Date: Thu, 23 Apr 2026 10:29:06 -0400 Subject: [PATCH] loop: refactor-session-activity completed after 1 iterations --- .../src/components/message/PromptInput.tsx | 18 ++++++----- .../useAutoPlayLastResponse.test.tsx | 30 +++++++++---------- frontend/src/hooks/useAutoPlayLastResponse.ts | 8 ++--- frontend/src/hooks/useOpenCode.ts | 4 +-- frontend/src/pages/SessionDetail.tsx | 9 +++--- 5 files changed, 36 insertions(+), 33 deletions(-) diff --git a/frontend/src/components/message/PromptInput.tsx b/frontend/src/components/message/PromptInput.tsx index 04f93845..ac52a2a1 100644 --- a/frontend/src/components/message/PromptInput.tsx +++ b/frontend/src/components/message/PromptInput.tsx @@ -62,7 +62,8 @@ interface PromptInputProps { repoId?: number disabled?: boolean showScrollButton?: boolean - hasActiveStream?: boolean + isSessionActive?: boolean + isStreamingResponse?: boolean onScrollToBottom?: () => void onShowSessionsDialog?: () => void onShowModelsDialog?: () => void @@ -79,7 +80,8 @@ export const PromptInput = memo(forwardRef( repoId, disabled, showScrollButton, - hasActiveStream = false, + isSessionActive = false, + isStreamingResponse = false, onScrollToBottom, onShowSessionsDialog, onShowModelsDialog, @@ -222,7 +224,7 @@ export const PromptInput = memo(forwardRef( pendingVoiceAutoSubmitRef.current = false setIsVoiceAutoSendPending(false) - if (hasActiveStream) { + if (isStreamingResponse) { const parts = parsePromptToParts(prompt, attachedFiles, imageAttachments) const agentUsed = selectedAgent || currentMode sendPrompt.mutate({ @@ -925,8 +927,8 @@ const { model, modelString, setModel: setStoredModel } = useModelSelection(opcod const { setShowDialog, hasForSession: hasPermissionsForSession } = usePermissions() const hasPendingPermissionForSession = hasPermissionsForSession(sessionID) const { hasVariants, currentVariant, cycleVariant } = useVariants(opcodeUrl, directory) - const showStopButton = hasActiveStream - const hideSecondaryButtons = isMobile && hasActiveStream + const showStopButton = isSessionActive + const hideSecondaryButtons = isMobile && isSessionActive const showVoiceFeedback = isVoiceHoldActive || isRecording || isTogglingRecording || isProcessing || isVoiceAutoSendPending const voiceFeedbackLabel = isProcessing ? isVoiceAutoSendPending @@ -1063,7 +1065,7 @@ return ( isBashMode={isBashMode} disabled={disabled} /> - {hasActiveStream ? ( + {isSessionActive ? (
@@ -1198,9 +1200,9 @@ return ( ? 'bg-orange-500 hover:bg-orange-600 border-orange-400 text-primary-foreground ring-orange-500/20' : 'bg-primary hover:bg-primary/90 disabled:bg-muted disabled:text-muted-foreground disabled:cursor-not-allowed text-primary-foreground border-white/30' }`} - title={hasPendingPermissionForSession ? 'View pending permission' : (hasActiveStream ? 'Queue message' : 'Send')} + title={hasPendingPermissionForSession ? 'View pending permission' : (isStreamingResponse ? 'Queue message' : 'Send')} > - {hasPendingPermissionForSession ? 'View' : (hasActiveStream ? 'Queue' : 'Send')} + {hasPendingPermissionForSession ? 'View' : (isStreamingResponse ? 'Queue' : 'Send')} diff --git a/frontend/src/hooks/__tests__/useAutoPlayLastResponse.test.tsx b/frontend/src/hooks/__tests__/useAutoPlayLastResponse.test.tsx index 45acf792..359aa39d 100644 --- a/frontend/src/hooks/__tests__/useAutoPlayLastResponse.test.tsx +++ b/frontend/src/hooks/__tests__/useAutoPlayLastResponse.test.tsx @@ -126,7 +126,7 @@ describe('useAutoPlayLastResponse', () => { sessionId: 'test-session', lastAssistantMessage: message, lastAssistantText: 'Test text', - hasActiveStream: false, + isStreamingResponse: false, }) ) @@ -142,7 +142,7 @@ describe('useAutoPlayLastResponse', () => { sessionId: 'test-session', lastAssistantMessage: message, lastAssistantText: 'Test text', - hasActiveStream: false, + isStreamingResponse: false, }) ) @@ -158,7 +158,7 @@ describe('useAutoPlayLastResponse', () => { sessionId: 'test-session', lastAssistantMessage: message, lastAssistantText: 'Test text', - hasActiveStream: false, + isStreamingResponse: false, }) ) @@ -176,7 +176,7 @@ describe('useAutoPlayLastResponse', () => { sessionId: 'test-session', lastAssistantMessage: incompleteMessage, lastAssistantText: 'Test text', - hasActiveStream: false, + isStreamingResponse: false, }, } ) @@ -188,7 +188,7 @@ describe('useAutoPlayLastResponse', () => { sessionId: 'test-session', lastAssistantMessage: completedMessage, lastAssistantText: 'Test text', - hasActiveStream: false, + isStreamingResponse: false, }) expect(mockSpeakMessage).toHaveBeenCalledTimes(1) @@ -206,7 +206,7 @@ describe('useAutoPlayLastResponse', () => { sessionId: 'test-session', lastAssistantMessage: message, lastAssistantText: 'Test text', - hasActiveStream: false, + isStreamingResponse: false, }, } ) @@ -217,7 +217,7 @@ describe('useAutoPlayLastResponse', () => { sessionId: 'test-session', lastAssistantMessage: message, lastAssistantText: 'Test text', - hasActiveStream: false, + isStreamingResponse: false, }) expect(mockSpeakMessage).not.toHaveBeenCalled() @@ -235,7 +235,7 @@ describe('useAutoPlayLastResponse', () => { sessionId: 'test-session', lastAssistantMessage: firstMessage, lastAssistantText: 'First text', - hasActiveStream: false, + isStreamingResponse: false, }, } ) @@ -247,7 +247,7 @@ describe('useAutoPlayLastResponse', () => { sessionId: 'test-session', lastAssistantMessage: secondMessage, lastAssistantText: 'Second text', - hasActiveStream: false, + isStreamingResponse: false, }) expect(mockSpeakMessage).toHaveBeenCalledTimes(1) @@ -266,7 +266,7 @@ describe('useAutoPlayLastResponse', () => { sessionId: 'session-1', lastAssistantMessage: message1, lastAssistantText: 'Session 1 text', - hasActiveStream: false, + isStreamingResponse: false, }, } ) @@ -278,14 +278,14 @@ describe('useAutoPlayLastResponse', () => { sessionId: 'session-2', lastAssistantMessage: message2, lastAssistantText: 'Session 2 text', - hasActiveStream: false, + isStreamingResponse: false, }) expect(mockSpeakMessage).toHaveBeenCalledTimes(1) expect(mockSpeakMessage).toHaveBeenCalledWith('1', 'Session 2 text') }) - it('does NOT call speakMessage when hasActiveStream is true', () => { + it('does NOT call speakMessage when isStreamingResponse is true', () => { setup() const message = createMessage('1', Date.now()) @@ -294,7 +294,7 @@ describe('useAutoPlayLastResponse', () => { sessionId: 'test-session', lastAssistantMessage: message, lastAssistantText: 'Test text', - hasActiveStream: true, + isStreamingResponse: true, }) ) @@ -310,7 +310,7 @@ describe('useAutoPlayLastResponse', () => { sessionId: 'test-session', lastAssistantMessage: message, lastAssistantText: '', - hasActiveStream: false, + isStreamingResponse: false, }) ) @@ -326,7 +326,7 @@ describe('useAutoPlayLastResponse', () => { sessionId: 'test-session', lastAssistantMessage: message, lastAssistantText: ' ', - hasActiveStream: false, + isStreamingResponse: false, }) ) diff --git a/frontend/src/hooks/useAutoPlayLastResponse.ts b/frontend/src/hooks/useAutoPlayLastResponse.ts index e63e4ca4..7e71ed7c 100644 --- a/frontend/src/hooks/useAutoPlayLastResponse.ts +++ b/frontend/src/hooks/useAutoPlayLastResponse.ts @@ -7,7 +7,7 @@ interface UseAutoPlayLastResponseParams { sessionId: string lastAssistantMessage: MessageWithParts | undefined lastAssistantText: string - hasActiveStream: boolean + isStreamingResponse: boolean } function isMessageCompleted(message: MessageWithParts['info']): boolean { @@ -18,7 +18,7 @@ export function useAutoPlayLastResponse({ sessionId, lastAssistantMessage, lastAssistantText, - hasActiveStream, + isStreamingResponse, }: UseAutoPlayLastResponseParams): void { const { speakMessage, isEnabled: ttsEnabled } = useTTS() const { preferences } = useSettings() @@ -52,7 +52,7 @@ export function useAutoPlayLastResponse({ return } - if (hasActiveStream || !lastAssistantMessage) { + if (isStreamingResponse || !lastAssistantMessage) { return } @@ -94,7 +94,7 @@ export function useAutoPlayLastResponse({ }, [ ttsEnabled, autoPlayEnabled, - hasActiveStream, + isStreamingResponse, lastAssistantMessage, lastAssistantText, speakMessage, diff --git a/frontend/src/hooks/useOpenCode.ts b/frontend/src/hooks/useOpenCode.ts index 3a410345..70135aa2 100644 --- a/frontend/src/hooks/useOpenCode.ts +++ b/frontend/src/hooks/useOpenCode.ts @@ -436,13 +436,13 @@ export const useAbortSession = ( const queryKey = ["opencode", "messages", opcodeUrl, targetSessionID, directory]; const messages = queryClient.getQueryData(queryKey); - const hasActiveStream = messages?.some(msgWithParts => { + const hasIncompleteMessages = messages?.some(msgWithParts => { if (msgWithParts.info.role !== "assistant") return false; const assistantInfo = msgWithParts.info as AssistantMessage; return !assistantInfo.time.completed; }); - return !hasActiveStream; + return !hasIncompleteMessages; }, [queryClient, opcodeUrl, directory]); useEffect(() => { diff --git a/frontend/src/pages/SessionDetail.tsx b/frontend/src/pages/SessionDetail.tsx index d35d68c7..454aac30 100644 --- a/frontend/src/pages/SessionDetail.tsx +++ b/frontend/src/pages/SessionDetail.tsx @@ -158,13 +158,13 @@ export function SessionDetail() { const lastAssistantMessage = messages?.filter(m => m.info.role === 'assistant').at(-1); const lastAssistantText = (lastAssistantMessage?.parts ?? []).filter(p => p.type === 'text').map(p => p.text).join('\n\n') || ''; const hasIncompleteMessages = lastAssistantMessage ? !('completed' in lastAssistantMessage.info.time && lastAssistantMessage.info.time.completed) : false; - const hasActiveStream = hasIncompleteMessages && isSessionActive; + const isStreamingResponse = hasIncompleteMessages && isSessionActive; useAutoPlayLastResponse({ sessionId: sessionId ?? '', lastAssistantMessage, lastAssistantText, - hasActiveStream, + isStreamingResponse, }); const handleShowModelsDialog = useCallback(() => setModelDialogOpen(true), []); @@ -511,7 +511,7 @@ export function SessionDetail() { >
- {ttsEnabled && !hasPromptContent && !hasActiveStream && lastAssistantMessage && lastAssistantText && ( + {ttsEnabled && !hasPromptContent && !isStreamingResponse && lastAssistantMessage && lastAssistantText && (