Complemento de llamada de voz
Llamada de voz (complemento)
Sección titulada «Llamada de voz (complemento)»Llamadas de voz para OpenClaw a través de un complemento. Soporta notificaciones salientes y conversaciones de varios turnos con políticas entrantes.
Proveedores actuales:
twilio(Voz programable + Transmisiones de medios)telnyx(Control de llamadas v2)plivo(API de voz + transferencia XML + voz GetInput)mock(desarrollo/sin red)
Modelo mental rápido:
- Instalar complemento
- Reiniciar Gateway
- Configurar en
plugins.entries.voice-call.config - Usar
openclaw voicecall ...o la herramientavoice_call
Dónde se ejecuta (local vs remoto)
Sección titulada «Dónde se ejecuta (local vs remoto)»El complemento de llamada de voz se ejecuta dentro del proceso del Gateway.
Si utiliza un Gateway remoto, instale/configure el complemento en la máquina que ejecuta el Gateway y luego reinicie el Gateway para cargarlo.
Instalación
Sección titulada «Instalación»Opción A: instalar desde npm (recomendado)
Sección titulada «Opción A: instalar desde npm (recomendado)»openclaw plugins install @openclaw/voice-callReinicie el Gateway después.
Opción B: instalar desde una carpeta local (desarrollo, sin copia)
Sección titulada «Opción B: instalar desde una carpeta local (desarrollo, sin copia)»PLUGIN_SRC=./path/to/local/voice-call-pluginopenclaw plugins install "$PLUGIN_SRC"cd "$PLUGIN_SRC" && pnpm installReinicie el Gateway después.
Configuración
Sección titulada «Configuración»Establezca la configuración en plugins.entries.voice-call.config:
{ plugins: { entries: { "voice-call": { enabled: true, config: { provider: "twilio", // or "telnyx" | "plivo" | "mock" fromNumber: "+15550001234", toNumber: "+15550005678",
twilio: { accountSid: "ACxxxxxxxx", authToken: "...", },
telnyx: { apiKey: "...", connectionId: "...", // Telnyx webhook public key from the Telnyx Mission Control Portal // (Base64 string; can also be set via TELNYX_PUBLIC_KEY). publicKey: "...", },
plivo: { authId: "MAxxxxxxxxxxxxxxxxxxxx", authToken: "...", },
// Webhook server serve: { port: 3334, path: "/voice/webhook", },
// Webhook security (recommended for tunnels/proxies) webhookSecurity: { allowedHosts: ["voice.example.com"], trustedProxyIPs: ["100.64.0.1"], },
// Public exposure (pick one) // publicUrl: "https://example.ngrok.app/voice/webhook", // tunnel: { provider: "ngrok" }, // tailscale: { mode: "funnel", path: "/voice/webhook" }
outbound: { defaultMode: "notify", // notify | conversation },
streaming: { enabled: true, streamPath: "/voice/stream", preStartTimeoutMs: 5000, maxPendingConnections: 32, maxPendingConnectionsPerIp: 4, maxConnections: 128, }, }, }, }, },}Notas:
- Twilio/Telnyx requieren una URL de webhook accesible públicamente.
- Plivo requiere una URL de webhook accesible públicamente.
mockes un proveedor de desarrollo local (sin llamadas a la red).- Telnyx requiere
telnyx.publicKey(oTELNYX_PUBLIC_KEY) a menos queskipSignatureVerificationsea verdadero. skipSignatureVerificationes solo para pruebas locales.- Si usa el nivel gratuito de ngrok, configure
publicUrlen la URL exacta de ngrok; siempre se exige la verificación de firma. tunnel.allowNgrokFreeTierLoopbackBypass: truepermite webhooks de Twilio con firmas no válidas solo cuandotunnel.provider="ngrok"yserve.bindes loopback (agente local ngrok). Use solo para desarrollo local.- Las URL del nivel gratuito de Ngrok pueden cambiar o agregar un comportamiento intersticial; si
publicUrlcambia, las firmas de Twilio fallarán. Para producción, prefiera un dominio estable o un embudo Tailscale. - Valores predeterminados de seguridad de transmisión:
streaming.preStartTimeoutMscierra los sockets que nunca envían un marcostartválido.streaming.maxPendingConnectionslimita el total de sockets de preinicio no autenticados.streaming.maxPendingConnectionsPerIplimita los sockets de preinicio no autenticados por IP de origen.streaming.maxConnectionslimita el total de sockets de flujo de medios abiertos (pendientes + activos).
Segadora de llamadas obsoletas
Sección titulada «Segadora de llamadas obsoletas»Use staleCallReaperSeconds para finalizar llamadas que nunca reciben un webhook terminal
(por ejemplo, llamadas en modo de notificación que nunca se completan). El valor predeterminado es 0
(deshabilitado).
Rangos recomendados:
- Producción:
120–300segundos para flujos de estilo de notificación. - Mantenga este valor más alto que
maxDurationSecondspara que las llamadas normales puedan finalizar. Un buen punto de partida esmaxDurationSeconds + 30–60segundos.
Ejemplo:
{ plugins: { entries: { "voice-call": { config: { maxDurationSeconds: 300, staleCallReaperSeconds: 360, }, }, }, },}Seguridad del Webhook
Sección titulada «Seguridad del Webhook»Cuando un proxy o túnel se encuentra delante de la puerta de enlace (Gateway), el complemento reconstruye la URL pública para la verificación de firmas. Estas opciones controlan qué encabezados reenviados son de confianza.
webhookSecurity.allowedHosts pone en la lista blanca los hosts de los encabezados de reenvío.
webhookSecurity.trustForwardingHeaders confía en los encabezados reenviados sin una lista blanca.
webhookSecurity.trustedProxyIPs solo confía en los encabezados reenviados cuando la IP
remota de la solicitud coincide con la lista.
La protección de repetición de webhook está habilitada para Twilio y Plivo. Las solicitudes de webhook válidas repetidas se reconocen pero se omiten para efectos secundarios.
Los turnos de conversación de Twilio incluyen un token por turno en las devoluciones de llamada <Gather>, por lo que
las devoluciones de llamada de voz obsoletas/repetidas no pueden satisfacer un turno de transcripción pendiente más reciente.
Las solicitudes de webhook no autenticadas se rechazan antes de leer el cuerpo cuando faltan los encabezados de firma requeridos por el proveedor.
El webhook de voz utiliza el perfil de cuerpo previo a la autenticación compartido (64 KB / 5 segundos) más un límite de solicitudes simultáneas por IP antes de la verificación de la firma.
Ejemplo con un host público estable:
{ plugins: { entries: { "voice-call": { config: { publicUrl: "https://voice.example.com/voice/webhook", webhookSecurity: { allowedHosts: ["voice.example.com"], }, }, }, }, },}TTS para llamadas
Sección titulada «TTS para llamadas»Voice Call utiliza la configuración principal messages.tts para transmitir voz en las llamadas. Puede anularla en la configuración del complemento con el mismo formato; se fusiona profundamente con messages.tts.
{ tts: { provider: "elevenlabs", providers: { elevenlabs: { voiceId: "pMsXgVXv3BLzUgSXRplE", modelId: "eleven_multilingual_v2", }, }, },}Notas:
- Las claves
tts.<provider>heredadas dentro de la configuración del complemento (openai,elevenlabs,microsoft,edge) se migran automáticamente atts.providers.<provider>al cargar. Prefiera la formaprovidersen la configuración guardada. - Microsoft speech se ignora para las llamadas de voz (el audio de telefonía necesita PCM; el transporte actual de Microsoft no expone la salida PCM de telefonía).
- Se usa el TTS central cuando el streaming de medios de Twilio está habilitado; de lo contrario, las llamadas vuelven a las voces nativas del proveedor.
- Si ya hay un stream de medios de Twilio activo, Voice Call no vuelve al TwiML
<Say>. Si el TTS de telefonía no está disponible en ese estado, la solicitud de reproducción falla en lugar de mezclar dos rutas de reproducción. - Cuando el TTS de telefonía vuelve a un proveedor secundario, Voice Call registra una advertencia con la cadena de proveedores (
from,to,attempts) para depuración.
Más ejemplos
Sección titulada «Más ejemplos»Usar solo el TTS central (sin invalidación):
{ messages: { tts: { provider: "openai", providers: { openai: { voice: "alloy" }, }, }, },}Invalidar a ElevenLabs solo para llamadas (mantener el valor predeterminado central en otros lugares):
{ plugins: { entries: { "voice-call": { config: { tts: { provider: "elevenlabs", providers: { elevenlabs: { apiKey: "elevenlabs_key", voiceId: "pMsXgVXv3BLzUgSXRplE", modelId: "eleven_multilingual_v2", }, }, }, }, }, }, },}Invalidar solo el modelo de OpenAI para llamadas (ejemplo de fusión profunda):
{ plugins: { entries: { "voice-call": { config: { tts: { providers: { openai: { model: "gpt-4o-mini-tts", voice: "marin", }, }, }, }, }, }, },}Llamadas entrantes
Sección titulada «Llamadas entrantes»La política de entrada tiene como valor predeterminado disabled. Para habilitar las llamadas entrantes, configure:
{ inboundPolicy: "allowlist", allowFrom: ["+15550001234"], inboundGreeting: "Hello! How can I help?",}inboundPolicy: "allowlist" es un filtro de identificación de llamada de baja seguridad. El complemento
normaliza el valor From proporcionado por el proveedor y lo compara con allowFrom.
La verificación del webhook autentica la entrega del proveedor y la integridad de la carga útil, pero
no prueba la propiedad del número de llamante PSTN/VoIP. Trate allowFrom como
filtrado de identificación de llamada, no como una identidad de llamada fuerte.
Las respuestas automáticas usan el sistema de agentes. Ajuste con:
responseModelresponseSystemPromptresponseTimeoutMs
Contrato de salida hablada
Sección titulada «Contrato de salida hablada»Para las respuestas automáticas, Voice Call añade un contrato estricto de salida hablada al mensaje del sistema:
{"spoken":"..."}
Luego, Voice Call extrae el texto de voz de forma defensiva:
- Ignora las cargas útiles marcadas como contenido de razonamiento/error.
- Analiza JSON directo, JSON cercado o claves
"spoken"en línea. - Revierte a texto sin formato y elimina los párrafos iniciales probables de planificación/metadatos.
Esto mantiene la reproducción hablada centrada en el texto orientado al llamante y evita filtrar texto de planificación en el audio.
Comportamiento de inicio de la conversación
Sección titulada «Comportamiento de inicio de la conversación»Para las llamadas conversation salientes, el manejo del primer mensaje está vinculado al estado de reproducción en vivo:
- La limpieza de la cola de interrupción y la respuesta automática se suprimen solo mientras el saludo inicial se está reproduciendo activamente.
- Si la reproducción inicial falla, la llamada vuelve a
listeningy el mensaje inicial permanece en cola para reintentar. - La reproducción inicial para el streaming de Twilio comienza al conectar el flujo sin retraso adicional.
Período de gracia de desconexión del flujo de Twilio
Sección titulada «Período de gracia de desconexión del flujo de Twilio»Cuando se desconecta un flujo de medios de Twilio, Voice Call espera 2000ms antes de finalizar automáticamente la llamada:
- Si el flujo se vuelve a conectar durante ese período, la finalización automática se cancela.
- Si no se vuelve a registrar ningún flujo después del período de gracia, la llamada finaliza para evitar llamadas activas atascadas.
openclaw voicecall call --to "+15555550123" --message "Hello from OpenClaw"openclaw voicecall start --to "+15555550123" # alias for callopenclaw voicecall continue --call-id <id> --message "Any questions?"openclaw voicecall speak --call-id <id> --message "One moment"openclaw voicecall end --call-id <id>openclaw voicecall status --call-id <id>openclaw voicecall tailopenclaw voicecall latency # summarize turn latency from logsopenclaw voicecall expose --mode funnellatency lee calls.jsonl desde la ruta de almacenamiento predeterminada de voice-call. Use
--file <path> para señalar un registro diferente y --last <n> para limitar el análisis
a los últimos N registros (predeterminado 200). La salida incluye p50/p90/p99 para la latencia
de turno y los tiempos de espera de escucha.
Herramienta del agente
Sección titulada «Herramienta del agente»Nombre de la herramienta: voice_call
Acciones:
initiate_call(message, to?, mode?)continue_call(callId, message)speak_to_user(callId, message)end_call(callId)get_status(callId)
Este repositorio incluye un documento de habilidad coincidente en skills/voice-call/SKILL.md.
RPC de Gateway
Sección titulada «RPC de Gateway»voicecall.initiate(to?,message,mode?)voicecall.continue(callId,message)voicecall.speak(callId,message)voicecall.end(callId)voicecall.status(callId)