chenbhao Claude Big Pickle commited on
Commit
9004edd
·
1 Parent(s): b7c4c8f

fix: prevent TTS replay of historical messages on session resume

Browse files

useAutoTTS now detects session switches (resume) via UUID discontinuity
and treats all loaded messages as history to skip TTS. Only subsequent
real-time assistant replies will trigger speech.

Co-Authored-By: Claude Big Pickle <noreply@anthropic.com>

Files changed (1) hide show
  1. src/hooks/useAutoTTS.ts +28 -5
src/hooks/useAutoTTS.ts CHANGED
@@ -40,11 +40,34 @@ export function useAutoTTS(messages: RenderableMessage[], isLoading?: boolean):
40
  const settings = getInitialSettings()
41
  if (!settings.voiceAutoTTS || !settings.voiceEnabled) return
42
 
43
- // Capture history snapshot on the transition from idle active.
44
- // This fires once: when the user first submits a message in a fresh REPL,
45
- // or (importantly) never during a resume where isLoading stays false.
46
- if (!historyIdsRef.current && !wasLoadingRef.current && isLoading) {
47
- historyIdsRef.current = new Set(messages.map(m => m.uuid))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  }
49
  wasLoadingRef.current = isLoading ?? false
50
 
 
40
  const settings = getInitialSettings()
41
  if (!settings.voiceAutoTTS || !settings.voiceEnabled) return
42
 
43
+ // Detect session switch (mid-session /resume): if we already took a
44
+ // history snapshot for a previous session but the incoming messages are
45
+ // entirely different (no overlapping UUIDs), reset and re-snapshot so the
46
+ // resumed session's history isn't re-spoken.
47
+ if (historyIdsRef.current && messages.length > 0) {
48
+ const isSessionSwitch = messages.every(
49
+ m => !historyIdsRef.current!.has(m.uuid),
50
+ )
51
+ if (isSessionSwitch) {
52
+ historyIdsRef.current = null
53
+ wasLoadingRef.current = false
54
+ }
55
+ }
56
+
57
+ // Capture history snapshot on the transition from idle → active, or on
58
+ // first render with pre-loaded messages (resume path).
59
+ if (!historyIdsRef.current && !wasLoadingRef.current) {
60
+ if (isLoading || messages.length > 0) {
61
+ // Normal path (isLoading=true): user just submitted their first
62
+ // message in a fresh session. Snapshot current messages so pre-loaded
63
+ // tool-call results / system messages are excluded from TTS.
64
+ //
65
+ // Resume path (messages.length>0, isLoading=false): messages were
66
+ // pre-loaded without a loading transition (e.g. /resume,
67
+ // --resume-session). Treat all displayed messages as history so they
68
+ // are not re-spoken. Only subsequent real-time replies will be spoken.
69
+ historyIdsRef.current = new Set(messages.map(m => m.uuid))
70
+ }
71
  }
72
  wasLoadingRef.current = isLoading ?? false
73