Ciclo de vida de la superposición de voz (macOS)
Público: colaboradores de la app para macOS. Objetivo: mantener predecible la superposición de voz cuando se solapan la palabra de activación y push-to-talk.Intención actual
- Si la superposición ya está visible por la palabra de activación y el usuario pulsa la tecla rápida, la sesión de tecla rápida adopta el texto existente en lugar de restablecerlo. La superposición permanece visible mientras se mantenga pulsada la tecla. Cuando el usuario la suelta: enviar si hay texto con espacios recortados; de lo contrario, descartar.
- La palabra de activación por sí sola sigue enviándose automáticamente al detectar silencio; push-to-talk envía inmediatamente al soltar.
Implementado (9 de diciembre de 2025)
- Las sesiones de superposición ahora llevan un token por captura (palabra de activación o push-to-talk). Las actualizaciones parciales/finales/de envío/de descarte/de nivel se descartan cuando el token no coincide, evitando callbacks obsoletos.
- Push-to-talk adopta cualquier texto de superposición visible como prefijo (así, al pulsar la tecla rápida mientras la superposición de activación está visible se conserva el texto y se añade el nuevo habla). Espera hasta 1,5 s por una transcripción final antes de recurrir al texto actual.
- El registro de chime/superposición se emite en
infoen las categoríasvoicewake.overlay,voicewake.pttyvoicewake.chime(inicio de sesión, parcial, final, envío, descarte, motivo del chime).
Próximos pasos
- VoiceSessionCoordinator (actor)
- Mantiene exactamente una
VoiceSessiona la vez. - API (basada en tokens):
beginWakeCapture,beginPushToTalk,updatePartial,endCapture,cancel,applyCooldown. - Descarta callbacks que lleven tokens obsoletos (evita que reconocedores antiguos vuelvan a abrir la superposición).
- Mantiene exactamente una
- VoiceSession (modelo)
- Campos:
token,source(wakeWord|pushToTalk), texto confirmado/volátil, indicadores de chime, temporizadores (auto-send, idle),overlayMode(display|editing|sending), fecha límite de cooldown.
- Campos:
- Vinculación de superposición
VoiceSessionPublisher(ObservableObject) refleja la sesión activa en SwiftUI.VoiceWakeOverlayViewrenderiza solo mediante el publisher; nunca muta directamente singletons globales.- Las acciones del usuario sobre la superposición (
sendNow,dismiss,edit) llaman de vuelta al coordinador con el token de sesión.
- Ruta de envío unificada
- En
endCapture: si el texto recortado está vacío → descartar; si no,performSend(session:)(reproduce el chime de envío una vez, reenvía, descarta). - Push-to-talk: sin retraso; palabra de activación: retraso opcional para envío automático.
- Aplica un cooldown corto al runtime de activación después de terminar push-to-talk para que la palabra de activación no se vuelva a disparar inmediatamente.
- En
- Registro
- El coordinador emite registros
.infoen el subsistemaai.openclaw, categoríasvoicewake.overlayyvoicewake.chime. - Eventos clave:
session_started,adopted_by_push_to_talk,partial,finalized,send,dismiss,cancel,cooldown.
- El coordinador emite registros
Lista de comprobación de depuración
-
Transmite los registros mientras reproduces una superposición bloqueada:
- Verifica que solo haya un token de sesión activo; el coordinador debe descartar los callbacks obsoletos.
-
Asegúrate de que al soltar push-to-talk siempre se llame a
endCapturecon el token activo; si el texto está vacío, esperadismisssin chime ni envío.
Pasos de migración (sugeridos)
- Agregar
VoiceSessionCoordinator,VoiceSessionyVoiceSessionPublisher. - Refactorizar
VoiceWakeRuntimepara crear/actualizar/finalizar sesiones en lugar de tocarVoiceWakeOverlayControllerdirectamente. - Refactorizar
VoicePushToTalkpara adoptar sesiones existentes y llamar aendCaptureal soltar; aplicar cooldown al runtime. - Conectar
VoiceWakeOverlayControlleral publisher; eliminar llamadas directas desde runtime/PTT. - Agregar pruebas de integración para adopción de sesiones, cooldown y descarte con texto vacío.