Voice Overlay Lifecycle (macOS)
Zielgruppe: macOS App Contributors. Ziel: Das Voice Overlay vorhersehbar halten, wenn Wake-Word und Push-to-Talk sich überlappen.
Aktuelle Absicht
- Wenn das Overlay bereits durch das Wake-Word sichtbar ist und du den Hotkey drückst, übernimmt die Hotkey-Session den vorhandenen Text, anstatt ihn zurückzusetzen. Das Overlay bleibt offen, solange du den Hotkey gedrückt hältst. Beim Loslassen: Senden, falls getrimmter Text vorhanden ist, sonst schließen.
- Wake-Word allein sendet weiterhin automatisch bei Stille; Push-to-Talk sendet sofort beim Loslassen.
Implementiert (9. Dezember 2025)
- Overlay Sessions tragen jetzt ein Token pro Capture (Wake-Word oder Push-to-Talk). Partial/Final/Send/Dismiss/Level Updates werden verworfen, wenn das Token nicht übereinstimmt – so werden veraltete Callbacks vermieden.
- Push-to-Talk übernimmt sichtbaren Overlay-Text als Präfix (wenn du also den Hotkey drückst, während das Wake-Overlay offen ist, bleibt der Text erhalten und neue Sprache wird angehängt). Es wartet bis zu 1,5 Sekunden auf ein finales Transkript, bevor es auf den aktuellen Text zurückfällt.
- Chime/Overlay Logging wird auf
info-Level in den Kategorienvoicewake.overlay,voicewake.pttundvoicewake.chimeausgegeben (Session Start, Partial, Final, Send, Dismiss, Chime Reason).
Nächste Schritte
- VoiceSessionCoordinator (Actor)
- Verwaltet genau eine
VoiceSessiongleichzeitig. - API (Token-basiert):
beginWakeCapture,beginPushToTalk,updatePartial,endCapture,cancel,applyCooldown. - Verwirft Callbacks mit veralteten Tokens (verhindert, dass alte Recognizer das Overlay erneut öffnen).
- Verwaltet genau eine
- VoiceSession (Model)
- Felder:
token,source(wakeWord|pushToTalk), committed/volatile Text, Chime Flags, Timer (auto-send, idle),overlayMode(display|editing|sending), Cooldown Deadline.
- Felder:
- Overlay Binding
VoiceSessionPublisher(ObservableObject) spiegelt die aktive Session in SwiftUI.VoiceWakeOverlayViewrendert nur über den Publisher; es mutiert niemals direkt globale Singletons.- Overlay User Actions (
sendNow,dismiss,edit) rufen den Coordinator mit dem Session Token auf.
- Unified Send Path
- Bei
endCapture: Wenn getrimmter Text leer ist → schließen; sonstperformSend(session:)(spielt Send Chime einmal ab, leitet weiter, schließt). - Push-to-Talk: keine Verzögerung; Wake-Word: optionale Verzögerung für Auto-Send.
- Wende eine kurze Cooldown-Phase auf die Wake Runtime an, nachdem Push-to-Talk beendet ist, damit Wake-Word nicht sofort erneut triggert.
- Bei
- Logging
- Coordinator gibt
.infoLogs im Subsystembot.moltaus, Kategorienvoicewake.overlayundvoicewake.chime. - Wichtige Events:
session_started,adopted_by_push_to_talk,partial,finalized,send,dismiss,cancel,cooldown.
- Coordinator gibt
Debugging Checklist
-
Streame Logs, während du ein klebendes Overlay reproduzierst:
sudo log stream --predicate 'subsystem == "bot.molt" AND category CONTAINS "voicewake"' --level info --style compact -
Prüfe, dass nur ein aktives Session Token existiert; veraltete Callbacks sollten vom Coordinator verworfen werden.
-
Stelle sicher, dass Push-to-Talk Release immer
endCapturemit dem aktiven Token aufruft; wenn Text leer ist, erwartedismissohne Chime oder Send.
Migrations-Schritte (Vorschlag)
- Füge
VoiceSessionCoordinator,VoiceSessionundVoiceSessionPublisherhinzu. - Refaktoriere
VoiceWakeRuntime, um Sessions zu erstellen/aktualisieren/beenden, anstattVoiceWakeOverlayControllerdirekt zu berühren. - Refaktoriere
VoicePushToTalk, um bestehende Sessions zu übernehmen undendCapturebeim Loslassen aufzurufen; wende Runtime Cooldown an. - Verbinde
VoiceWakeOverlayControllermit dem Publisher; entferne direkte Aufrufe von Runtime/PTT. - Füge Integrationstests für Session Adoption, Cooldown und Empty-Text Dismissal hinzu.