fix: voice assistant disconnects after greeting with no error shown (#878)#909
fix: voice assistant disconnects after greeting with no error shown (#878)#909chris-yyau wants to merge 2 commits intoslopus:mainfrom
Conversation
…lopus#878) The onError handler silently set status to 'disconnected' for ALL errors, including runtime failures after the greeting played. Users heard "Hi, Happy here" then saw the UI return to idle with no explanation. Changes: - Track `wasConnected` ref to distinguish init errors (silent) from post-connection errors (set status to 'error') - onDisconnect preserves 'error' status if onError already fired - Status bar shows "Voice disconnected — tap to dismiss" on error - Tapping the error bar dismisses it Applies to both native and web voice session components. Addresses slopus#878 Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
There was a problem hiding this comment.
Pull request overview
This PR fixes a UX bug where the voice assistant could disconnect after the greeting without surfacing an error to the user, by distinguishing initialization-time failures (silent) from post-connection runtime failures (visible error state) and allowing the error banner to be dismissed.
Changes:
- Track a
wasConnectedref inRealtimeVoiceSession(native + web) to show'error'only for runtime failures after a successful connection. - Update
onDisconnectto avoid overwriting an existing'error'status set byonError. - Update the status bar error message and allow tapping to dismiss the error banner.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| packages/happy-app/sources/realtime/RealtimeVoiceSession.tsx | Adds wasConnected tracking and preserves 'error' status across disconnects on native. |
| packages/happy-app/sources/realtime/RealtimeVoiceSession.web.tsx | Same runtime-vs-init error handling and status preservation for web. |
| packages/happy-app/sources/components/VoiceAssistantStatusBar.tsx | Changes error-state messaging and adds tap-to-dismiss behavior for the error banner. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| import { View, Text, Pressable, StyleSheet, Platform } from 'react-native'; | ||
| import { useSafeAreaInsets } from 'react-native-safe-area-context'; |
There was a problem hiding this comment.
useSafeAreaInsets and Platform are imported but never used in this component. Please remove unused imports to keep the file clean and avoid future lint/typecheck tightening causing failures.
| import { View, Text, Pressable, StyleSheet, Platform } from 'react-native'; | |
| import { useSafeAreaInsets } from 'react-native-safe-area-context'; | |
| import { View, Text, Pressable, StyleSheet } from 'react-native'; |
| backgroundColor: theme.colors.surfaceHighest, | ||
| isPulsing: false, | ||
| text: 'Connection Error', | ||
| text: 'Voice disconnected — tap to dismiss', |
There was a problem hiding this comment.
The error-state copy says “tap to dismiss”, but the full-width layout still renders the right-side hint as “Tap to end”. This results in conflicting instructions when realtimeStatus === 'error'. Update the UI copy/conditional rendering so the interaction hint matches the error behavior.
| text: 'Voice disconnected — tap to dismiss', | |
| text: 'Voice disconnected — tap to end', |
- Remove unused `Platform` and `useSafeAreaInsets` imports - Right-side hint now shows "Tap to dismiss" in error state instead of "Tap to end" (which conflicted with left-side "Voice disconnected") Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
Summary
Fixes the voice assistant silently disconnecting after "Hi, Happy here" with no feedback to the user. 4+ users reported this (#878).
RealtimeVoiceSession.tsx+.web.tsx: TrackwasConnectedref to distinguish initialization errors (silent — prevents startup "Terminals error") from post-connection errors (set status to'error').onDisconnectnow preserves'error'status instead of overwriting it.VoiceAssistantStatusBar.tsx: Error state shows "Voice disconnected — tap to dismiss" instead of being stuck. Tapping dismisses the bar.Root cause
The
onErrorhandler silently set status to'disconnected'for ALL errors, including runtime WebRTC failures after the greeting played. ThenonDisconnect(which fires immediately after) would overwrite any error state. Users saw the UI return to idle with no explanation.Note: This fix makes the disconnect visible but doesn't prevent it. The underlying disconnect is likely in the
@elevenlabs/react-nativeSDK's WebRTC layer.Addresses #878
Test plan
🤖 Generated with Claude Code via Happy