macOS companion app
Sprach-Overlay
Voice-Overlay-Lebenszyklus (macOS)
Zielgruppe: Mitwirkende an der macOS-App. Ziel: das Voice Overlay vorhersehbar halten, wenn Wake-Word und Push-to-Talk überlappen.
Aktuelle Absicht
- Wenn das Overlay durch ein Wake-Word bereits sichtbar ist und der Benutzer die Tastenkombination drückt, übernimmt die Hotkey-Sitzung den vorhandenen Text, statt ihn zurückzusetzen. Das Overlay bleibt sichtbar, solange die Tastenkombination gehalten wird. Wenn der Benutzer loslässt: 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-Sitzungen tragen jetzt ein Token pro Aufnahme (Wake-Word oder Push-to-Talk). Partial-/Final-/Send-/Dismiss-/Level-Updates werden verworfen, wenn das Token nicht übereinstimmt, wodurch veraltete Callbacks vermieden werden.
- Push-to-Talk übernimmt jeden sichtbaren Overlay-Text als Präfix (wenn also die Tastenkombination gedrückt wird, während das Wake-Overlay sichtbar ist, bleibt der Text erhalten und neue Sprache wird angehängt). Es wartet bis zu 1,5 s auf ein finales Transkript, bevor auf den aktuellen Text zurückgefallen wird.
- Chime-/Overlay-Logging wird auf
infoin den Kategorienvoicewake.overlay,voicewake.pttundvoicewake.chimeausgegeben (Sitzungsstart, partial, final, send, dismiss, Chime-Grund).
Nächste Schritte
- VoiceSessionCoordinator (actor)
- Besitzt zu jedem Zeitpunkt genau eine
VoiceSession. - API (tokenbasiert):
beginWakeCapture,beginPushToTalk,updatePartial,endCapture,cancel,applyCooldown. - Verwirft Callbacks mit veralteten Tokens (verhindert, dass alte Erkenner das Overlay erneut öffnen).
- Besitzt zu jedem Zeitpunkt genau eine
- VoiceSession (model)
- Felder:
token,source(wakeWord|pushToTalk), festgeschriebener/flüchtiger Text, Chime-Flags, Timer (Auto-Send, Idle),overlayMode(display|editing|sending), Cooldown-Frist.
- Felder:
- Overlay-Binding
VoiceSessionPublisher(ObservableObject) spiegelt die aktive Sitzung in SwiftUI.VoiceWakeOverlayViewrendert nur über den Publisher; es mutiert niemals globale Singletons direkt.- Overlay-Benutzeraktionen (
sendNow,dismiss,edit) rufen den Coordinator mit dem Sitzungstoken zurück.
- Vereinheitlichter Sendepfad
- Bei
endCapture: wenn getrimmter Text leer ist → schließen; andernfallsperformSend(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.
- Wenden Sie nach Abschluss von Push-to-Talk einen kurzen Cooldown auf die Wake-Laufzeit an, damit das Wake-Word nicht sofort erneut auslöst.
- Bei
- Logging
- Der Coordinator gibt
.info-Logs im Subsystemai.openclawund in den Kategorienvoicewake.overlayundvoicewake.chimeaus. - Wichtige Ereignisse:
session_started,adopted_by_push_to_talk,partial,finalized,send,dismiss,cancel,cooldown.
- Der Coordinator gibt
Debugging-Checkliste
-
Streamen Sie Logs, während Sie ein hängenbleibendes Overlay reproduzieren:
sudo log stream --predicate 'subsystem == "ai.openclaw" AND category CONTAINS "voicewake"' --level info --style compact -
Prüfen Sie, dass nur ein aktives Sitzungstoken vorhanden ist; veraltete Callbacks sollten vom Coordinator verworfen werden.
-
Stellen Sie sicher, dass das Loslassen von Push-to-Talk immer
endCapturemit dem aktiven Token aufruft; wenn der Text leer ist, erwarten Siedismissohne Chime oder Senden.
Migrationsschritte (vorgeschlagen)
VoiceSessionCoordinator,VoiceSessionundVoiceSessionPublisherhinzufügen.VoiceWakeRuntimeso refaktorieren, dass Sitzungen erstellt/aktualisiert/beendet werden, stattVoiceWakeOverlayControllerdirekt zu berühren.VoicePushToTalkso refaktorieren, dass vorhandene Sitzungen übernommen werden und beim LoslassenendCaptureaufgerufen wird; Runtime-Cooldown anwenden.VoiceWakeOverlayControllermit dem Publisher verdrahten; direkte Aufrufe aus Runtime/PTT entfernen.- Integrationstests für Sitzungsübernahme, Cooldown und Schließen bei leerem Text hinzufügen.