diff --git a/apps/desktop/src/app/chat/composer/hooks/use-voice-conversation.ts b/apps/desktop/src/app/chat/composer/hooks/use-voice-conversation.ts index 33285f05aa16..ea40a5fc2cc1 100644 --- a/apps/desktop/src/app/chat/composer/hooks/use-voice-conversation.ts +++ b/apps/desktop/src/app/chat/composer/hooks/use-voice-conversation.ts @@ -10,6 +10,7 @@ import { stopVoicePlayback } from '@/lib/voice-playback' import { notify, notifyError } from '@/store/notifications' +import { $voicePlayback } from '@/store/voice-playback' import { useMicRecorder } from './use-mic-recorder' @@ -54,6 +55,7 @@ export function useVoiceConversation({ const speechSessionRef = useRef(null) const stopBargeMonitorRef = useRef<(() => void) | null>(null) const bargeCapturePendingRef = useRef(false) + const speechStartSequenceRef = useRef(0) const enabledRef = useRef(enabled) const mutedRef = useRef(muted) const busyRef = useRef(busy) @@ -211,7 +213,16 @@ export function useVoiceConversation({ dropSpeechSession() - if (enabledRef.current) { + // If stopVoicePlayback() was called externally (Stop button, end), the + // voice-playback sequence has advanced past what we captured at speech + // start — don't auto-start the next sentence, the user chose to stop. + const stoppedByUser = + speechStartSequenceRef.current > 0 && + $voicePlayback.get().sequence > speechStartSequenceRef.current + + speechStartSequenceRef.current = 0 + + if (enabledRef.current && !stoppedByUser) { pendingStartRef.current = true } @@ -341,6 +352,8 @@ export function useVoiceConversation({ barged = true }) + speechStartSequenceRef.current = $voicePlayback.get().sequence + void playSpeechText(response.text, { source: 'voice-conversation' }) .catch(error => notifyError(error, voiceCopy.playbackFailed)) .finally(() => { @@ -365,6 +378,7 @@ export function useVoiceConversation({ (responseId: string) => { responseIdRef.current = responseId spokenSourceLengthRef.current = 0 + speechStartSequenceRef.current = $voicePlayback.get().sequence setStatus('speaking') let barged = false