Skip to content

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

PhaseWeekPlatformStatusDeliverables
1Week 1Backend + Shared✅ CompleteOrchestrator, unified endpoint, extended store
2Week 2Web✅ CompleteWeb voice unified, avatar modes, settings UI
3Week 3Mobile✅ CompleteiOS/Android unified, mobile settings
4Week 4tvOS✅ CompleteTV unified, TV-optimized UI
5Week 5All✅ CompleteCleanup, 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 managers

After 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 tracking

Phase-by-Phase Migration Details

Phase 1: Core Infrastructure (Week 1)

Goal: Build unified core without breaking existing systems

What Was Created

  1. Type Definitions (/shared/types/voiceAvatar.ts)

    typescript
    export type AvatarMode = 'full' | 'compact' | 'minimal' | 'icon_only';
    export type VoiceIntent = 'CHAT' | 'SEARCH' | 'NAVIGATION' | 'PLAYBACK' | 'SCROLL' | 'CONTROL';
    export interface VoiceConfig { ... }
    export interface VoiceCommandResponse { ... }
  2. Avatar Mode Constants (/shared/constants/voiceAvatarModes.ts)

    • Platform-specific dimensions
    • Feature toggles per mode
    • Platform availability matrix
  3. OlorinVoiceOrchestrator (/shared/services/olorinVoiceOrchestrator.ts)

    • Single entry point for all voice interactions
    • Platform-aware configuration
    • Conversation ID management
  4. supportStore Extension (/shared/stores/supportStore.ts)

    • Added avatarVisibilityMode state
    • Added currentInteractionType tracking
    • Added commandHistory array
    • LocalStorage/AsyncStorage persistence
  5. Backend Unified Endpoint (/backend/app/api/routes/voice/unified.py)

    • POST /api/v1/voice/unified
    • Request/response models
    • Authentication integration
  6. 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

  1. VoiceInteractionPanel (/shared/components/voice/VoiceInteractionPanel.tsx)

    • Unified panel for all modes
    • Platform-specific rendering
    • Smooth mode transitions
  2. useVoiceOrchestrator Hook (/shared/hooks/useVoiceOrchestrator.ts)

    • React integration
    • Lifecycle management
    • Error handling
  3. AvatarPreferencesSection (/web/src/components/settings/voice/components/AvatarPreferencesSection.tsx)

    • Web settings UI
    • 4 mode cards with previews
    • Real-time mode switching

What Was Modified

  1. VoiceAvatarFAB (/shared/components/support/VoiceAvatarFAB.tsx)

    • Added mode-aware visibility
    • Added wake word pulse animation
    • Trigger orchestrator on tap
  2. VoiceChatModal (/shared/components/support/VoiceChatModal.tsx)

    • Support all avatar modes
    • Mode transition animations
    • Collapse timer logic
  3. 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

  1. 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
    }
  2. 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

  1. 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

typescript
// 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

  1. 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
  2. Component Deprecation (/tvos-app/src/components/voice/index.ts)

    • Deprecated TVVoiceIndicator, TVVoiceWaveform, TVVoiceResponseDisplay
    • Exported shared VoiceInteractionPanel

What Was Created

  1. 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)
  2. 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

typescript
// 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

  1. /mobile-app/src/components/voice/VoiceSearchModal.tsx
  2. /mobile-app/src/components/voice/VoiceCommandButton.tsx
  3. /tvos-app/src/components/voice/TVVoiceIndicator.tsx
  4. /tvos-app/src/components/voice/TVVoiceWaveform.tsx
  5. /tvos-app/src/components/voice/TVVoiceResponseDisplay.tsx

What Was Created

  1. Architecture Documentation (/docs/architecture/UNIFIED_VOICE_ARCHITECTURE.md)
  2. Migration Guide (/docs/guides/VOICE_MIGRATION_GUIDE.md) - This document
  3. API Reference (/docs/api/VOICE_API_REFERENCE.md)

Performance Optimizations

  1. Intent classification caching
  2. Streaming mode default for faster responses
  3. Reduced spritesheet frame rate on low-end devices
  4. 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:

typescript
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:

typescript
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:

typescript
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:

typescript
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:

typescript
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

bash
# 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:voice

Troubleshooting

Common Issues After Migration

Issue 1: "orchestrator is null"

Symptom: Voice commands fail with null orchestrator error

Solution: Ensure orchestrator is initialized before use

typescript
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

typescript
// 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

python
# 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

typescript
// Ensure audio session is configured
await Audio.setAudioModeAsync({
  allowsRecordingIOS: true,
  playsInSilentModeIOS: true,
  shouldDuckAndroid: true,
});

Performance Monitoring

Key Metrics to Track

  1. Voice Command Volume

    • Commands per day
    • Commands per user
    • Peak usage times
  2. Intent Distribution

    • CHAT: ~40%
    • SEARCH: ~30%
    • PLAYBACK: ~15%
    • NAVIGATION: ~10%
    • SCROLL: ~3%
    • CONTROL: ~2%
  3. Latency

    • p50: ❤️.5s end-to-end
    • p95: <8s end-to-end
    • p99: <15s end-to-end
  4. 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

  1. Identify Breaking Commit

    bash
    git log --oneline --grep="Phase [1-5]"
  2. Create Rollback Branch

    bash
    git checkout -b rollback/voice-system
    git revert <commit-hash>
  3. Test Rollback

    bash
    npm run test:all
    poetry run pytest
  4. Deploy Rollback

    bash
    git push origin rollback/voice-system
    # Trigger deployment pipeline
  5. Notify 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


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

  1. Start with documentation early in the process
  2. Implement feature flags for easier rollback
  3. Create parallel systems for A/B testing before cutover
  4. Increase test coverage to 100% before deprecating old code
  5. 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

Released under the MIT License.