Skip to content

fix: voice assistant disconnects after greeting with no error shown (#878)#909

Open
chris-yyau wants to merge 2 commits intoslopus:mainfrom
chris-yyau:fix/voice-disconnect-878
Open

fix: voice assistant disconnects after greeting with no error shown (#878)#909
chris-yyau wants to merge 2 commits intoslopus:mainfrom
chris-yyau:fix/voice-disconnect-878

Conversation

@chris-yyau
Copy link
Copy Markdown
Contributor

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: Track wasConnected ref to distinguish initialization errors (silent — prevents startup "Terminals error") from post-connection errors (set status to 'error'). onDisconnect now 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 onError handler silently set status to 'disconnected' for ALL errors, including runtime WebRTC failures after the greeting played. Then onDisconnect (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-native SDK's WebRTC layer.

Addresses #878

Test plan

  • Voice assistant greeting + listening works normally when connection is stable
  • When connection drops after greeting, error bar appears with "Voice disconnected — tap to dismiss"
  • Tapping the error bar dismisses it
  • Startup initialization errors (no ElevenLabs) still degrade silently

🤖 Generated with Claude Code via Happy

…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>
Copilot AI review requested due to automatic review settings March 24, 2026 12:41
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 wasConnected ref in RealtimeVoiceSession (native + web) to show 'error' only for runtime failures after a successful connection.
  • Update onDisconnect to avoid overwriting an existing 'error' status set by onError.
  • 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.

Comment on lines 2 to 3
import { View, Text, Pressable, StyleSheet, Platform } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
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';

Copilot uses AI. Check for mistakes.
backgroundColor: theme.colors.surfaceHighest,
isPulsing: false,
text: 'Connection Error',
text: 'Voice disconnected — tap to dismiss',
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
text: 'Voice disconnected — tap to dismiss',
text: 'Voice disconnected — tap to end',

Copilot uses AI. Check for mistakes.
- 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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants