Voice-Overlay-Lebenszyklus (macOS)
Zielgruppe: macOS-App-Contributors. Ziel: das Voice-Overlay vorhersagbar halten, wenn Wake-Word und Push-to-Talk sich überlappen.
Aktuelle Absicht
- Wenn das Overlay bereits durch ein Wake-Word sichtbar ist und der Benutzer die Hotkey-Taste drückt, übernimmt die Hotkey-Session den bestehenden Text, statt ihn zurückzusetzen. Das Overlay bleibt sichtbar, solange die Taste gehalten wird. Beim Loslassen: senden wenn getrimmter Text vorhanden ist, andernfalls schließen.
- Wake-Word allein sendet weiterhin automatisch bei Stille; Push-to-Talk sendet sofort beim Loslassen.
Implementiert (9. Dez. 2025)
- Overlay-Sessions tragen jetzt ein Token pro Erfassung (Wake-Word oder Push-to-Talk). Partial/Final/Send/Dismiss/Level-Updates werden verworfen, wenn das Token nicht übereinstimmt, was veraltete Callbacks vermeidet.
- Push-to-Talk übernimmt sichtbaren Overlay-Text als Präfix (das Drücken der Hotkey-Taste während das Wake-Overlay oben ist, behält den Text und hängt neue Sprache an). Es wartet bis zu 1,5s 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-Grund).
Nächste Schritte
- VoiceSessionCoordinator (Actor)
- Besitzt 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).
- Besitzt 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 nach SwiftUI.VoiceWakeOverlayViewrendert nur über den Publisher; es ändert niemals globale Singletons direkt.- Overlay-Benutzeraktionen (
sendNow,dismiss,edit) rufen zurück in den Coordinator mit dem Session-Token.
- Einheitlicher Send-Pfad
- Bei
endCapture: wenn getrimmter Text leer ist → schließen; sonstperformSend(session:)(spielt Send-Chime einmal, leitet weiter, schließt). - Push-to-Talk: kein Delay; Wake-Word: optionales Delay für Auto-Send.
- Kurzen Cooldown auf die Wake-Runtime anwenden, nachdem Push-to-Talk beendet ist, damit Wake-Word nicht sofort erneut auslöst.
- Bei
- Logging
- Coordinator gibt
.info-Logs im Subsystemai.openclawaus, Kategorienvoicewake.overlayundvoicewake.chime. - Schlüssel-Events:
session_started,adopted_by_push_to_talk,partial,finalized,send,dismiss,cancel,cooldown.
- Coordinator gibt
Debugging-Checkliste
-
Logs streamen, während ein hängendes Overlay reproduziert wird:
sudo log stream --predicate 'subsystem == "ai.openclaw" AND category CONTAINS "voicewake"' --level info --style compact -
Prüfe, dass nur ein aktives Session-Token vorhanden ist; veraltete Callbacks sollten vom Coordinator verworfen werden.
-
Stelle sicher, dass das Loslassen von Push-to-Talk immer
endCapturemit dem aktiven Token aufruft; bei leerem Text erwartedismissohne Chime oder Send.
Migrationsschritte (vorgeschlagen)
VoiceSessionCoordinator,VoiceSessionundVoiceSessionPublisherhinzufügen.VoiceWakeRuntimerefaktorisieren, um Sessions zu erstellen/aktualisieren/beenden, stattVoiceWakeOverlayControllerdirekt anzusprechen.VoicePushToTalkrefaktorisieren, um bestehende Sessions zu übernehmen undendCapturebeim Loslassen aufzurufen; Runtime-Cooldown anwenden.VoiceWakeOverlayControlleran den Publisher binden; direkte Aufrufe aus Runtime/PTT entfernen.- Integrationstests für Session-Übernahme, Cooldown und Dismiss bei leerem Text hinzufügen.