macOS companion app
Superposición de voz
Ciclo de vida de la superposición de voz (macOS)
Público: colaboradores de la aplicación macOS. Objetivo: mantener predecible la superposición de voz cuando la palabra de activación y pulsar para hablar se superponen.
Intención actual
- Si la superposición ya está visible por la palabra de activación y el usuario pulsa la tecla de acceso rápido, la sesión de la tecla de acceso rápido adopta el texto existente en lugar de restablecerlo. La superposición permanece visible mientras se mantiene pulsada la tecla de acceso rápido. Cuando el usuario la suelta: envía si hay texto recortado; de lo contrario, descarta.
- Solo la palabra de activación sigue enviándose automáticamente al detectar silencio; pulsar para hablar envía inmediatamente al soltar.
Implementado (9 de dic. de 2025)
- Las sesiones de superposición ahora llevan un token por captura (palabra de activación o pulsar para hablar). Las actualizaciones parciales/finales/de envío/descarte/nivel se descartan cuando el token no coincide, lo que evita callbacks obsoletos.
- Pulsar para hablar adopta cualquier texto visible de la superposición como prefijo (por lo que pulsar la tecla de acceso rápido mientras la superposición de activación está visible conserva el texto y añade la nueva voz). Espera hasta 1,5 s una transcripción final antes de recurrir al texto actual.
- El registro de timbre/superposición se emite en
infoen las categoríasvoicewake.overlay,voicewake.pttyvoicewake.chime(inicio de sesión, parcial, final, envío, descarte, motivo del timbre).
Próximos pasos
- VoiceSessionCoordinator (actor)
- Posee exactamente una
VoiceSessiona la vez. - API (basada en tokens):
beginWakeCapture,beginPushToTalk,updatePartial,endCapture,cancel,applyCooldown. - Descarta callbacks que llevan tokens obsoletos (evita que reconocedores antiguos vuelvan a abrir la superposición).
- Posee exactamente una
- VoiceSession (modelo)
- Campos:
token,source(wakeWord|pushToTalk), texto confirmado/volátil, indicadores de timbre, temporizadores (envío automático, inactividad),overlayMode(display|editing|sending), fecha límite de enfriamiento.
- 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 de usuario de la superposición (
sendNow,dismiss,edit) vuelven a llamar 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 timbre de envío una vez, reenvía, descarta). - Pulsar para hablar: sin demora; palabra de activación: demora opcional para el envío automático.
- Aplica un enfriamiento breve al entorno de ejecución de activación después de que termine pulsar para hablar para que la palabra de activación no se reactive de inmediato.
- 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 persistente:
sudo log stream --predicate 'subsystem == "ai.openclaw" AND category CONTAINS "voicewake"' --level info --style compact -
Verifica que haya un solo token de sesión activo; el coordinador debe descartar los callbacks obsoletos.
-
Asegúrate de que soltar pulsar para hablar siempre llame a
endCapturecon el token activo; si el texto está vacío, esperadismisssin timbre ni envío.
Pasos de migración (sugeridos)
- Añade
VoiceSessionCoordinator,VoiceSessionyVoiceSessionPublisher. - Refactoriza
VoiceWakeRuntimepara crear/actualizar/finalizar sesiones en lugar de tocar directamenteVoiceWakeOverlayController. - Refactoriza
VoicePushToTalkpara adoptar sesiones existentes y llamar aendCaptureal soltar; aplica enfriamiento del entorno de ejecución. - Conecta
VoiceWakeOverlayControlleral publisher; elimina las llamadas directas desde el entorno de ejecución/PTT. - Añade pruebas de integración para adopción de sesiones, enfriamiento y descarte de texto vacío.