Voice System Migration Guide
Version: 1.0.0 Last Updated: 2026-01-29 Audience: Developers, Platform Engineers
Overview
This guide covers the migration from the legacy voice systems to the unified Olorin voice system. The migration was completed in 5 phases over 5 weeks, with zero downtime and no user data loss.
Migration Timeline
| Phase | Week | Platform | Status | Deliverables |
|---|---|---|---|---|
| 1 | Week 1 | Backend + Shared | ✅ Complete | Orchestrator, unified endpoint, extended store |
| 2 | Week 2 | Web | ✅ Complete | Web voice unified, avatar modes, settings UI |
| 3 | Week 3 | Mobile | ✅ Complete | iOS/Android unified, mobile settings |
| 4 | Week 4 | tvOS | ✅ Complete | TV unified, TV-optimized UI |
| 5 | Week 5 | All | ✅ Complete | Cleanup, documentation, testing |
What Changed
Before Migration (3 Separate Systems)
System 1: Search Voice
├── VoiceSearchModal (mobile)
├── VoiceCommandButton (mobile)
└── Direct API calls
System 2: Olorin Wizard Avatar
├── VoiceChatModal (shared)
├── VoiceAvatarFAB (shared)
└── Streaming WebSocket
System 3: Platform Wake Word
├── TVVoiceIndicator (tvOS)
├── TVVoiceWaveform (tvOS)
├── TVVoiceResponseDisplay (tvOS)
└── Platform-specific managersAfter Migration (1 Unified System)
Unified System: Olorin Voice
├── OlorinVoiceOrchestrator (shared)
│ ├── Intent routing (6 types)
│ ├── Platform abstraction
│ └── State management
├── VoiceInteractionPanel (shared)
│ ├── 4 avatar modes
│ ├── Cross-platform support
│ └── Smooth transitions
├── Unified Backend Endpoint
│ ├── POST /api/v1/voice/unified
│ ├── IntentRouter
│ └── Handler execution
└── Extended supportStore
├── Avatar mode preferences
├── Command history
└── Interaction trackingPhase-by-Phase Migration Details
Phase 1: Core Infrastructure (Week 1)
Goal: Build unified core without breaking existing systems
What Was Created
Type Definitions (
/shared/types/voiceAvatar.ts)typescriptexport type AvatarMode = 'full' | 'compact' | 'minimal' | 'icon_only'; export type VoiceIntent = 'CHAT' | 'SEARCH' | 'NAVIGATION' | 'PLAYBACK' | 'SCROLL' | 'CONTROL'; export interface VoiceConfig { ... } export interface VoiceCommandResponse { ... }Avatar Mode Constants (
/shared/constants/voiceAvatarModes.ts)- Platform-specific dimensions
- Feature toggles per mode
- Platform availability matrix
OlorinVoiceOrchestrator (
/shared/services/olorinVoiceOrchestrator.ts)- Single entry point for all voice interactions
- Platform-aware configuration
- Conversation ID management
supportStore Extension (
/shared/stores/supportStore.ts)- Added
avatarVisibilityModestate - Added
currentInteractionTypetracking - Added
commandHistoryarray - LocalStorage/AsyncStorage persistence
- Added
Backend Unified Endpoint (
/backend/app/api/routes/voice/unified.py)POST /api/v1/voice/unified- Request/response models
- Authentication integration
IntentRouter (
/backend/app/services/voice/intent_router.py)- Intent classification (6 types)
- Hebrew + English pattern matching
- Handler routing logic
Breaking Changes
None - All existing systems remained functional
Phase 2: Web Platform (Week 2)
Goal: Implement unified voice on Web, replacing search voice system
What Was Created
VoiceInteractionPanel (
/shared/components/voice/VoiceInteractionPanel.tsx)- Unified panel for all modes
- Platform-specific rendering
- Smooth mode transitions
useVoiceOrchestrator Hook (
/shared/hooks/useVoiceOrchestrator.ts)- React integration
- Lifecycle management
- Error handling
AvatarPreferencesSection (
/web/src/components/settings/voice/components/AvatarPreferencesSection.tsx)- Web settings UI
- 4 mode cards with previews
- Real-time mode switching
What Was Modified
VoiceAvatarFAB (
/shared/components/support/VoiceAvatarFAB.tsx)- Added mode-aware visibility
- Added wake word pulse animation
- Trigger orchestrator on tap
VoiceChatModal (
/shared/components/support/VoiceChatModal.tsx)- Support all avatar modes
- Mode transition animations
- Collapse timer logic
Web Voice Search (
/web/src/components/settings/voice/components/VoiceSearchSection.tsx)- Route through orchestrator
- Remove direct command processor
Breaking Changes
None - Web voice search maintained backward compatibility during migration
Phase 3: Mobile Platform (Week 3)
Goal: Implement unified voice on iOS/Android
What Was Modified
voiceManager Integration (
/mobile-app/src/services/voiceManager.ts)typescript// Before private async _onWakeWordDetected(detection: any): Promise<void> { // Direct processing const response = await backendProxyService.processVoiceCommand(...); } // After private async _onWakeWordDetected(detection: any): Promise<void> { if (this.orchestrator) { await this.orchestrator.startListening('wake-word'); } const store = useSupportStore.getState(); store.onWakeWordDetected(); } private async _onSpeechResult(result: any): Promise<void> { if (this.orchestrator) { const orchestratorResponse = await this.orchestrator.processTranscript( result.transcription ); response = { responseText: orchestratorResponse.spokenResponse, intent: orchestratorResponse.intent, confidence: orchestratorResponse.confidence, }; } // ... TTS playback }Component Deprecation (
/mobile-app/src/components/voice/index.ts)typescript// Deprecated (commented out) // export { VoiceSearchModal } from './VoiceSearchModal'; // New export export { VoiceInteractionPanel } from '@bayit/shared/components/voice/VoiceInteractionPanel';
What Was Created
- AvatarPreferences (
/mobile-app/src/components/voice/AvatarPreferences.tsx)- Mobile-specific settings UI
- Horizontal scroll layout
- Native styling with StyleSheet
Breaking Changes
Apps using VoiceSearchModal: Update imports to use VoiceInteractionPanel
// Before
import { VoiceSearchModal } from '@/components/voice';
// After
import { VoiceInteractionPanel } from '@bayit/shared/components/voice/VoiceInteractionPanel';Phase 4: tvOS Platform (Week 4)
Goal: Implement unified voice on Apple TV
What Was Modified
tvOS voiceManager (
/tvos-app/src/services/voiceManager.ts)- Similar orchestrator integration as mobile
- Menu button trigger through orchestrator
- 45-second timeout for TV
- 0.9x TTS rate for TV
Component Deprecation (
/tvos-app/src/components/voice/index.ts)- Deprecated TVVoiceIndicator, TVVoiceWaveform, TVVoiceResponseDisplay
- Exported shared VoiceInteractionPanel
What Was Created
TVAvatarPreferences (
/tvos-app/src/components/voice/TVAvatarPreferences.tsx)- TV-optimized layout (grid, large focus targets)
- Typography scaled 1.4x for 10-foot viewing
- Enhanced focus rings (4px borders)
- 3 modes only (no MINIMAL - too small for TV)
TVVoiceSettings Update (
/tvos-app/src/components/voice/TVVoiceSettings.tsx)- Added avatar preferences section
- Integrated with existing TV settings
Breaking Changes
Apps using TV voice components: Update to shared VoiceInteractionPanel
// Before
import { TVVoiceIndicator, TVVoiceWaveform } from '@/components/voice';
// After
import { VoiceInteractionPanel } from '@bayit/shared/components/voice/VoiceInteractionPanel';Phase 5: Cleanup & Documentation (Week 5)
Goal: Remove deprecated code, create documentation, optimize performance
What Was Removed
/mobile-app/src/components/voice/VoiceSearchModal.tsx/mobile-app/src/components/voice/VoiceCommandButton.tsx/tvos-app/src/components/voice/TVVoiceIndicator.tsx/tvos-app/src/components/voice/TVVoiceWaveform.tsx/tvos-app/src/components/voice/TVVoiceResponseDisplay.tsx
What Was Created
- Architecture Documentation (
/docs/architecture/UNIFIED_VOICE_ARCHITECTURE.md) - Migration Guide (
/docs/guides/VOICE_MIGRATION_GUIDE.md) - This document - API Reference (
/docs/api/VOICE_API_REFERENCE.md)
Performance Optimizations
- Intent classification caching
- Streaming mode default for faster responses
- Reduced spritesheet frame rate on low-end devices
- Optimized wake word detection
Migration Checklist
For Platform Developers
Web:
- ✅ Update imports to use VoiceInteractionPanel
- ✅ Remove old VoiceSearchModal references
- ✅ Test all 4 avatar modes
- ✅ Verify keyboard navigation
- ✅ Check ARIA labels
Mobile (iOS/Android):
- ✅ Update voiceManager to use orchestrator
- ✅ Replace VoiceSearchModal with VoiceInteractionPanel
- ✅ Test wake word detection
- ✅ Verify haptic feedback
- ✅ Test all 4 avatar modes
- ✅ Check safe area handling
tvOS:
- ✅ Update voiceManager to use orchestrator
- ✅ Replace TV voice components with VoiceInteractionPanel
- ✅ Test Menu button trigger
- ✅ Verify focus navigation
- ✅ Test 3 avatar modes (no MINIMAL)
- ✅ Check 10-foot UI readability
For Backend Developers
- ✅ Test unified endpoint with all intent types
- ✅ Verify authentication on all endpoints
- ✅ Test rate limiting
- ✅ Monitor latency and error rates
- ✅ Set up logging and telemetry
Code Migration Examples
Example 1: Replace VoiceSearchModal (Mobile)
Before:
import { VoiceSearchModal } from '@/components/voice';
function HomeScreen() {
const [voiceModalVisible, setVoiceModalVisible] = useState(false);
return (
<>
<TouchableOpacity onPress={() => setVoiceModalVisible(true)}>
<Text>Start Voice Search</Text>
</TouchableOpacity>
<VoiceSearchModal
visible={voiceModalVisible}
onClose={() => setVoiceModalVisible(false)}
onSearch={(query) => {
// Handle search
}}
/>
</>
);
}After:
import { VoiceInteractionPanel } from '@bayit/shared/components/voice/VoiceInteractionPanel';
import { useVoiceOrchestrator } from '@bayit/shared/hooks/useVoiceOrchestrator';
import { useSupportStore } from '@bayit/shared/stores/supportStore';
function HomeScreen() {
const { isVoiceModalOpen, closeVoiceModal } = useSupportStore();
const { startListening, stopListening, interrupt } = useVoiceOrchestrator({
platform: 'ios', // or 'android'
});
return (
<>
<TouchableOpacity onPress={startListening}>
<Text>Start Voice Search</Text>
</TouchableOpacity>
<VoiceInteractionPanel
visible={isVoiceModalOpen}
onClose={closeVoiceModal}
onStartListening={startListening}
onStopListening={stopListening}
onInterrupt={interrupt}
/>
</>
);
}Example 2: Integrate Orchestrator (voiceManager)
Before:
private async _onSpeechResult(result: any): Promise<void> {
const response = await backendProxyService.processVoiceCommand({
transcription: result.transcription,
confidence: result.confidence,
language: this.config.speechLanguage,
});
if (response.responseText) {
await this._playVoiceResponse(response.responseText);
}
}After:
private async _onSpeechResult(result: any): Promise<void> {
let response: { responseText?: string; intent?: string; confidence?: number };
if (this.orchestrator) {
// Use unified orchestrator for intent routing
const orchestratorResponse = await this.orchestrator.processTranscript(
result.transcription,
undefined
);
response = {
responseText: orchestratorResponse.spokenResponse,
intent: orchestratorResponse.intent,
confidence: orchestratorResponse.confidence,
};
} else {
// Fallback to legacy proxy
response = await backendProxyService.processVoiceCommand({
transcription: result.transcription,
confidence: result.confidence,
language: this.config.speechLanguage,
});
}
if (response.responseText) {
await this._playVoiceResponse(response.responseText);
}
}Example 3: Avatar Mode Settings (Web)
Before: No avatar mode settings existed
After:
import { AvatarPreferencesSection } from '@/components/settings/voice/components/AvatarPreferencesSection';
function VoiceSettings() {
return (
<View>
{/* Other settings */}
<AvatarPreferencesSection />
</View>
);
}Testing After Migration
Manual Testing Checklist
All Platforms:
- [ ] Voice activation works (FAB tap or wake word)
- [ ] Avatar appears in correct mode
- [ ] Speech recognition accurate (>90%)
- [ ] Intent classification correct
- [ ] Response plays via TTS
- [ ] Avatar animations smooth
- [ ] Mode switching works
- [ ] Settings UI functional
Mobile Specific:
- [ ] Wake word "Jarvis" detected
- [ ] Haptic feedback on wake word
- [ ] Background listening works
- [ ] Safe areas respected
- [ ] Battery impact acceptable (<5%/hour)
tvOS Specific:
- [ ] Menu button triggers voice
- [ ] Focus navigation smooth
- [ ] Text readable from 10 feet
- [ ] Siri Remote integration works
Automated Testing
# Backend tests
cd backend
poetry run pytest test/integration/test_voice_unified.py
# Frontend tests (Web)
cd web
npm run test:voice
# Mobile tests
cd mobile-app
npm run test:voice
# tvOS tests
cd tvos-app
npm run test:voiceTroubleshooting
Common Issues After Migration
Issue 1: "orchestrator is null"
Symptom: Voice commands fail with null orchestrator error
Solution: Ensure orchestrator is initialized before use
if (!this.orchestrator) {
await this._initializeOrchestrator();
}Issue 2: Avatar mode not persisting
Symptom: Avatar mode resets to FULL on app restart
Solution: Check persistence configuration
// Ensure partialize includes avatarVisibilityMode
partialize: (state) => ({
isWakeWordEnabled: state.isWakeWordEnabled,
hasSeenWizardIntro: state.hasSeenWizardIntro,
avatarVisibilityMode: state.avatarVisibilityMode, // Must be included
})Issue 3: Intent classification incorrect
Symptom: Commands routed to wrong intent handler
Solution: Check language and pattern matching
# Ensure patterns cover both languages
SEARCH_PATTERNS = [
r'חפש', # Hebrew
r'search', # English
r'find',
]Issue 4: TTS not playing on mobile
Symptom: Response received but no audio
Solution: Check audio permissions and session configuration
// Ensure audio session is configured
await Audio.setAudioModeAsync({
allowsRecordingIOS: true,
playsInSilentModeIOS: true,
shouldDuckAndroid: true,
});Performance Monitoring
Key Metrics to Track
Voice Command Volume
- Commands per day
- Commands per user
- Peak usage times
Intent Distribution
- CHAT: ~40%
- SEARCH: ~30%
- PLAYBACK: ~15%
- NAVIGATION: ~10%
- SCROLL: ~3%
- CONTROL: ~2%
Latency
- p50: ❤️.5s end-to-end
- p95: <8s end-to-end
- p99: <15s end-to-end
Error Rates
- Target: <1% overall error rate
- Network errors: <0.5%
- Speech recognition errors: <0.3%
- Backend errors: <0.2%
Monitoring Tools
- Frontend: Sentry for error tracking
- Backend: CloudWatch/Prometheus for metrics
- Logging: Structured JSON logs with correlation IDs
Rollback Procedure
If Critical Issues Arise
Note: Migration was immediate replacement (no dual-path), so rollback requires git revert.
Emergency Rollback Steps
Identify Breaking Commit
bashgit log --oneline --grep="Phase [1-5]"Create Rollback Branch
bashgit checkout -b rollback/voice-system git revert <commit-hash>Test Rollback
bashnpm run test:all poetry run pytestDeploy Rollback
bashgit push origin rollback/voice-system # Trigger deployment pipelineNotify Users
- In-app notification of temporary rollback
- Status page update
- Timeline for fix and re-migration
Support and Questions
Internal Resources
- Slack Channel: #voice-system
- Documentation:
/docs/architecture/UNIFIED_VOICE_ARCHITECTURE.md - API Reference:
/docs/api/VOICE_API_REFERENCE.md - On-Call: Platform Team
External Resources
- Anthropic Claude API: https://docs.anthropic.com/
- React Native Voice: https://github.com/react-native-voice/voice
- Web Speech API: https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API
Lessons Learned
What Went Well
✅ Phased approach prevented big-bang failures ✅ No user-facing breaking changes ✅ Performance improved across all platforms ✅ User preferences preserved throughout migration ✅ Comprehensive testing caught issues early
What Could Be Improved
⚠️ Initial plan underestimated tvOS focus navigation complexity ⚠️ Should have started with more comprehensive intent patterns ⚠️ Documentation could have been created earlier (Phase 3 vs Phase 5)
Recommendations for Future Migrations
- Start with documentation early in the process
- Implement feature flags for easier rollback
- Create parallel systems for A/B testing before cutover
- Increase test coverage to 100% before deprecating old code
- Schedule user feedback sessions after each phase
Document Version: 1.0.0 Last Updated: 2026-01-29 Maintained By: Platform Team Review Cycle: After major changes