Cycle de vie de la superposition vocale (macOS)
Public : contributeurs de l’application macOS. Objectif : garder la superposition vocale prévisible lorsque le mot d’activation et le push-to-talk se chevauchent.Intention actuelle
- Si la superposition est déjà visible à cause du mot d’activation et que l’utilisateur appuie sur le raccourci, la session du raccourci adopte le texte existant au lieu de le réinitialiser. La superposition reste affichée tant que le raccourci est maintenu. Lorsque l’utilisateur relâche : envoyer s’il y a du texte une fois nettoyé, sinon fermer.
- Le mot d’activation seul continue à envoyer automatiquement au silence ; le push-to-talk envoie immédiatement au relâchement.
Implémenté (9 déc. 2025)
- Les sessions de superposition transportent maintenant un jeton par capture (mot d’activation ou push-to-talk). Les mises à jour partial/final/send/dismiss/level sont ignorées lorsque le jeton ne correspond pas, ce qui évite les callbacks obsolètes.
- Le push-to-talk adopte tout texte visible de la superposition comme préfixe (ainsi, appuyer sur le raccourci pendant que la superposition de réveil est active conserve le texte et ajoute la nouvelle parole). Il attend jusqu’à 1,5 s pour une transcription finale avant de revenir au texte actuel.
- Les journaux de carillon/superposition sont émis en
infodans les catégoriesvoicewake.overlay,voicewake.pttetvoicewake.chime(début de session, partiel, final, envoi, fermeture, raison du carillon).
Étapes suivantes
- VoiceSessionCoordinator (actor)
- Possède exactement une
VoiceSessionà la fois. - API (basée sur jeton) :
beginWakeCapture,beginPushToTalk,updatePartial,endCapture,cancel,applyCooldown. - Ignore les callbacks qui transportent des jetons obsolètes (empêche les anciens recognizers de rouvrir la superposition).
- Possède exactement une
- VoiceSession (modèle)
- Champs :
token,source(wakeWord|pushToTalk), texte validé/volatile, drapeaux de carillon, timers (auto-send, idle),overlayMode(display|editing|sending), échéance de cooldown.
- Champs :
- Liaison de superposition
VoiceSessionPublisher(ObservableObject) reflète la session active dans SwiftUI.VoiceWakeOverlayViews’affiche uniquement via le publisher ; il ne modifie jamais directement des singletons globaux.- Les actions utilisateur de la superposition (
sendNow,dismiss,edit) rappellent le coordinator avec le jeton de session.
- Chemin d’envoi unifié
- À
endCapture: si le texte nettoyé est vide → fermer ; sinonperformSend(session:)(joue une seule fois le carillon d’envoi, transfère, ferme). - Push-to-talk : pas de délai ; mot d’activation : délai facultatif pour l’envoi automatique.
- Appliquer un court cooldown au runtime de réveil après la fin du push-to-talk afin que le mot d’activation ne se redéclenche pas immédiatement.
- À
- Journalisation
- Le coordinator émet des journaux
.infodans le sous-systèmeai.openclaw, catégoriesvoicewake.overlayetvoicewake.chime. - Événements clés :
session_started,adopted_by_push_to_talk,partial,finalized,send,dismiss,cancel,cooldown.
- Le coordinator émet des journaux
Liste de contrôle de débogage
-
Diffusez les journaux pendant la reproduction d’une superposition bloquée :
- Vérifiez qu’un seul jeton de session est actif ; les callbacks obsolètes doivent être ignorés par le coordinator.
-
Assurez-vous que le relâchement du push-to-talk appelle toujours
endCaptureavec le jeton actif ; si le texte est vide, attendez-vous àdismisssans carillon ni envoi.
Étapes de migration (suggestion)
- Ajouter
VoiceSessionCoordinator,VoiceSessionetVoiceSessionPublisher. - Refactoriser
VoiceWakeRuntimepour créer/mettre à jour/terminer les sessions au lieu de toucher directementVoiceWakeOverlayController. - Refactoriser
VoicePushToTalkpour adopter les sessions existantes et appelerendCaptureau relâchement ; appliquer le cooldown runtime. - Connecter
VoiceWakeOverlayControllerau publisher ; supprimer les appels directs depuis runtime/PTT. - Ajouter des tests d’intégration pour l’adoption de session, le cooldown et la fermeture sur texte vide.