Plugins
Plugin de chamada de voz
Chamadas de voz para OpenClaw via um plugin. Suporta notificações de saída, conversas de múltiplos turnos, voz realtime full-duplex, transcrição por streaming e chamadas de entrada com políticas de lista de permissões.
Provedores atuais: twilio (Programmable Voice + Media Streams),
telnyx (Call Control v2), plivo (Voice API + XML transfer + GetInput
speech), mock (dev/sem rede).
Início rápido
Instale o plugin
Do npm
openclaw plugins install @openclaw/voice-call
De uma pasta local (dev)
PLUGIN_SRC=./path/to/local/voice-call-plugin
openclaw plugins install "$PLUGIN_SRC"
cd "$PLUGIN_SRC" && pnpm install
Use o pacote sem versão para acompanhar a tag de lançamento oficial atual. Fixe uma versão exata apenas quando precisar de uma instalação reproduzível.
Reinicie o Gateway depois para que o plugin seja carregado.
Configure o provedor e o webhook
Defina a configuração em plugins.entries.voice-call.config (veja
Configuração abaixo para a estrutura completa). No mínimo:
provider, credenciais do provedor, fromNumber e uma URL de webhook
acessível publicamente.
Verifique a configuração
openclaw voicecall setup
A saída padrão é legível em logs de chat e terminais. Ela verifica
a ativação do plugin, credenciais do provedor, exposição do webhook e se
apenas um modo de áudio (streaming ou realtime) está ativo. Use
--json para scripts.
Teste de fumaça
openclaw voicecall smoke
openclaw voicecall smoke --to "+15555550123"
Ambos são simulações por padrão. Adicione --yes para realmente fazer uma
breve chamada de notificação de saída:
openclaw voicecall smoke --to "+15555550123" --yes
Configuração
Se enabled: true, mas o provedor selecionado não tiver credenciais,
a inicialização do Gateway registra um aviso de configuração incompleta com as chaves ausentes e
ignora a inicialização do runtime. Comandos, chamadas RPC e ferramentas de agente ainda
retornam a configuração exata ausente do provedor quando usados.
{
plugins: {
entries: {
"voice-call": {
enabled: true,
config: {
provider: "twilio", // or "telnyx" | "plivo" | "mock"
fromNumber: "+15550001234", // or TWILIO_FROM_NUMBER for Twilio
toNumber: "+15550005678",
sessionScope: "per-phone", // per-phone | per-call
numbers: {
"+15550009999": {
inboundGreeting: "Silver Fox Cards, how can I help?",
responseSystemPrompt: "You are a concise baseball card specialist.",
tts: {
providers: {
openai: { voice: "alloy" },
},
},
},
},
twilio: {
accountSid: "ACxxxxxxxx",
authToken: "...",
},
telnyx: {
apiKey: "...",
connectionId: "...",
// Telnyx webhook public key from the Mission Control Portal
// (Base64; 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 /* see Streaming transcription */ },
realtime: { enabled: false /* see Realtime voice */ },
},
},
},
},
}
Notas de exposição e segurança do provedor
- Twilio, Telnyx e Plivo exigem uma URL de webhook acessível publicamente.
mocké um provedor de desenvolvimento local (sem chamadas de rede).- Telnyx exige
telnyx.publicKey(ouTELNYX_PUBLIC_KEY), a menos queskipSignatureVerificationseja true. skipSignatureVerificationé apenas para testes locais.- No nível gratuito do ngrok, defina
publicUrlcomo a URL exata do ngrok; a verificação de assinatura é sempre aplicada. tunnel.allowNgrokFreeTierLoopbackBypass: truepermite webhooks da Twilio com assinaturas inválidas somente quandotunnel.provider="ngrok"eserve.bindé loopback (agente local do ngrok). Apenas desenvolvimento local.- URLs do nível gratuito do Ngrok podem mudar ou adicionar comportamento intersticial; se
publicUrlmudar, as assinaturas da Twilio falham. Produção: prefira um domínio estável ou um funil do Tailscale.
Limites de conexão de streaming
streaming.preStartTimeoutMsfecha sockets que nunca enviam um framestartválido.streaming.maxPendingConnectionslimita o total de sockets pré-início não autenticados.streaming.maxPendingConnectionsPerIplimita sockets pré-início não autenticados por IP de origem.streaming.maxConnectionslimita o total de sockets de stream de mídia abertos (pendentes + ativos).
Migrações de configuração legada
Configurações antigas que usam provider: "log", twilio.from ou chaves OpenAI
legadas em streaming.* são reescritas por openclaw doctor --fix.
O fallback de runtime ainda aceita as chaves antigas de voice-call por enquanto, mas
o caminho de reescrita é openclaw doctor --fix e o shim de compatibilidade é
temporário.
Chaves de streaming migradas automaticamente:
streaming.sttProvider→streaming.providerstreaming.openaiApiKey→streaming.providers.openai.apiKeystreaming.sttModel→streaming.providers.openai.modelstreaming.silenceDurationMs→streaming.providers.openai.silenceDurationMsstreaming.vadThreshold→streaming.providers.openai.vadThreshold
Escopo da sessão
Por padrão, Voice Call usa sessionScope: "per-phone" para que chamadas repetidas do
mesmo chamador mantenham a memória da conversa. Defina sessionScope: "per-call" quando
cada chamada da operadora deve começar com contexto novo, por exemplo recepção,
reserva, IVR ou fluxos de ponte do Google Meet em que o mesmo número de telefone pode
representar reuniões diferentes.
Conversas de voz realtime
realtime seleciona um provedor de voz realtime full-duplex para áudio de chamada
ao vivo. Ele é separado de streaming, que apenas encaminha áudio para
provedores de transcrição realtime.
Comportamento atual do runtime:
realtime.enabledé compatível com Twilio Media Streams.realtime.provideré opcional. Se não estiver definido, Voice Call usa o primeiro provedor de voz realtime registrado.- Provedores de voz realtime incluídos: Google Gemini Live (
google) e OpenAI (openai), registrados pelos respectivos plugins de provedor. - A configuração bruta de propriedade do provedor fica em
realtime.providers.<providerId>. - Voice Call expõe a ferramenta realtime compartilhada
openclaw_agent_consultpor padrão. O modelo realtime pode chamá-la quando o chamador pedir raciocínio mais profundo, informações atuais ou ferramentas normais do OpenClaw. realtime.consultPolicyadiciona opcionalmente orientação para quando o modelo realtime deve chamaropenclaw_agent_consult.realtime.agentContext.enabledé desativado por padrão. Quando ativado, Voice Call injeta uma identidade de agente limitada, substituição de prompt do sistema e cápsula selecionada de arquivo de workspace nas instruções do provedor realtime durante a configuração da sessão.realtime.fastContext.enabledé desativado por padrão. Quando ativado, Voice Call primeiro pesquisa memória indexada/contexto de sessão para a pergunta de consulta e retorna esses trechos ao modelo realtime dentro derealtime.fastContext.timeoutMs, antes de fazer fallback para o agente de consulta completo somente serealtime.fastContext.fallbackToConsultfor true.- Se
realtime.providerapontar para um provedor não registrado, ou se nenhum provedor de voz realtime estiver registrado, Voice Call registra um aviso e ignora a mídia realtime em vez de falhar o plugin inteiro. - As chaves de sessão de consulta reutilizam a sessão de chamada armazenada quando disponível e depois fazem fallback para o
sessionScopeconfigurado (per-phonepor padrão, ouper-callpara chamadas isoladas).
Política de ferramentas
realtime.toolPolicy controla a execução da consulta:
| Política | Comportamento |
|---|---|
safe-read-only |
Expõe a ferramenta de consulta e limita o agente regular a read, web_search, web_fetch, x_search, memory_search e memory_get. |
owner |
Expõe a ferramenta de consulta e permite que o agente regular use a política normal de ferramentas do agente. |
none |
Não expõe a ferramenta de consulta. realtime.tools personalizadas ainda são repassadas ao provedor realtime. |
realtime.consultPolicy controla apenas as instruções do modelo realtime:
| Política | Orientação |
|---|---|
auto |
Mantém o prompt padrão e deixa o provedor decidir quando chamar a ferramenta de consulta. |
substantive |
Responde diretamente a conectivos conversacionais simples e consulta antes de fatos, memória, ferramentas ou contexto. |
always |
Consulta antes de cada resposta substantiva. |
Contexto de voz do agente
Ative realtime.agentContext quando a ponte de voz deve soar como o
agente OpenClaw configurado sem pagar uma viagem completa de consulta ao agente em
turnos comuns. A cápsula de contexto é adicionada uma vez quando a sessão realtime é
criada, portanto não adiciona latência por turno. Chamadas para
openclaw_agent_consult ainda executam o agente OpenClaw completo e devem ser usadas
para trabalho com ferramentas, informações atuais, buscas de memória ou estado do workspace.
{
plugins: {
entries: {
"voice-call": {
config: {
agentId: "main",
realtime: {
enabled: true,
provider: "google",
toolPolicy: "safe-read-only",
consultPolicy: "substantive",
agentContext: {
enabled: true,
maxChars: 6000,
includeIdentity: true,
includeSystemPrompt: true,
includeWorkspaceFiles: true,
files: ["SOUL.md", "IDENTITY.md", "USER.md"],
},
},
},
},
},
},
}
Exemplos de provedores em tempo real
Google Gemini Live
Padrões: chave de API de realtime.providers.google.apiKey,
GEMINI_API_KEY ou GOOGLE_GENERATIVE_AI_API_KEY; modelo
gemini-2.5-flash-native-audio-preview-12-2025; voz Kore.
sessionResumption e contextWindowCompression são ativados por padrão para chamadas mais longas
e reconectáveis. Use silenceDurationMs, startSensitivity e
endSensitivity para ajustar a alternância de turno mais rápida em áudio de telefonia.
{
plugins: {
entries: {
"voice-call": {
config: {
provider: "twilio",
inboundPolicy: "allowlist",
allowFrom: ["+15550005678"],
realtime: {
enabled: true,
provider: "google",
instructions: "Speak briefly. Call openclaw_agent_consult before using deeper tools.",
toolPolicy: "safe-read-only",
consultPolicy: "substantive",
agentContext: { enabled: true },
providers: {
google: {
apiKey: "${GEMINI_API_KEY}",
model: "gemini-2.5-flash-native-audio-preview-12-2025",
voice: "Kore",
silenceDurationMs: 500,
startSensitivity: "high",
},
},
},
},
},
},
},
}
OpenAI
{
plugins: {
entries: {
"voice-call": {
config: {
realtime: {
enabled: true,
provider: "openai",
providers: {
openai: { apiKey: "${OPENAI_API_KEY}" },
},
},
},
},
},
},
}
Consulte provedor do Google e provedor da OpenAI para opções de voz em tempo real específicas de cada provedor.
Transcrição por streaming
streaming seleciona um provedor de transcrição em tempo real para áudio de chamada ao vivo.
Comportamento atual em runtime:
streaming.provideré opcional. Se não definido, o Voice Call usa o primeiro provedor de transcrição em tempo real registrado.- Provedores de transcrição em tempo real incluídos: Deepgram (
deepgram), ElevenLabs (elevenlabs), Mistral (mistral), OpenAI (openai) e xAI (xai), registrados por seus plugins de provedor. - A configuração bruta pertencente ao provedor fica em
streaming.providers.<providerId>. - Depois que o Twilio envia uma mensagem
startde stream aceita, o Voice Call registra o stream imediatamente, enfileira mídia de entrada pelo provedor de transcrição enquanto o provedor se conecta e inicia a saudação inicial somente depois que a transcrição em tempo real está pronta. - Se
streaming.providerapontar para um provedor não registrado, ou nenhum estiver registrado, o Voice Call registra um aviso e ignora o streaming de mídia em vez de falhar o plugin inteiro.
Exemplos de provedores de streaming
OpenAI
Padrões: chave de API streaming.providers.openai.apiKey ou
OPENAI_API_KEY; modelo gpt-4o-transcribe; silenceDurationMs: 800;
vadThreshold: 0.5.
{
plugins: {
entries: {
"voice-call": {
config: {
streaming: {
enabled: true,
provider: "openai",
streamPath: "/voice/stream",
providers: {
openai: {
apiKey: "sk-...", // optional if OPENAI_API_KEY is set
model: "gpt-4o-transcribe",
silenceDurationMs: 800,
vadThreshold: 0.5,
},
},
},
},
},
},
},
}
xAI
Padrões: chave de API streaming.providers.xai.apiKey ou XAI_API_KEY;
endpoint wss://api.x.ai/v1/stt; codificação mulaw; taxa de amostragem 8000;
endpointingMs: 800; interimResults: true.
{
plugins: {
entries: {
"voice-call": {
config: {
streaming: {
enabled: true,
provider: "xai",
streamPath: "/voice/stream",
providers: {
xai: {
apiKey: "${XAI_API_KEY}", // optional if XAI_API_KEY is set
endpointingMs: 800,
language: "en",
},
},
},
},
},
},
},
}
TTS para chamadas
O Voice Call usa a configuração central messages.tts para fala por streaming
em chamadas. Você pode substituí-la na configuração do plugin com o
mesmo formato — ela faz deep merge com messages.tts.
{
tts: {
provider: "elevenlabs",
providers: {
elevenlabs: {
voiceId: "pMsXgVXv3BLzUgSXRplE",
modelId: "eleven_multilingual_v2",
},
},
},
}
Observações de comportamento:
- Chaves legadas
tts.<provider>dentro da configuração do plugin (openai,elevenlabs,microsoft,edge) são reparadas poropenclaw doctor --fix; a configuração confirmada deve usartts.providers.<provider>. - O TTS central é usado quando o streaming de mídia do Twilio está ativado; caso contrário, as chamadas retornam às vozes nativas do provedor.
- Se um stream de mídia do Twilio já estiver ativo, o Voice Call não retorna para
OPENCLAW_DOCS_MARKER:calloutOpen:U2F5do TwiML. Se o TTS de telefonia estiver indisponível nesse estado, a solicitação de reprodução falha em vez de misturar dois caminhos de reprodução. - Quando o TTS de telefonia retorna para um provedor secundário, o Voice Call registra um aviso com a cadeia de provedores (
from,to,attempts) para depuração. - Quando a interrupção por fala do Twilio ou o encerramento do stream limpa a fila pendente de TTS, as solicitações de reprodução enfileiradas são concluídas em vez de deixar chamadores aguardando a conclusão da reprodução indefinidamente.
Exemplos de TTS
Core TTS only
{
messages: {
tts: {
provider: "openai",
providers: {
openai: { voice: "alloy" },
},
},
},
}
Override to ElevenLabs (calls only)
{
plugins: {
entries: {
"voice-call": {
config: {
tts: {
provider: "elevenlabs",
providers: {
elevenlabs: {
apiKey: "elevenlabs_key",
voiceId: "pMsXgVXv3BLzUgSXRplE",
modelId: "eleven_multilingual_v2",
},
},
},
},
},
},
},
}
OpenAI model override (deep-merge)
{
plugins: {
entries: {
"voice-call": {
config: {
tts: {
providers: {
openai: {
model: "gpt-4o-mini-tts",
voice: "marin",
},
},
},
},
},
},
},
}
Chamadas de entrada
A política de entrada usa disabled por padrão. Para ativar chamadas de entrada, defina:
{
inboundPolicy: "allowlist",
allowFrom: ["+15550001234"],
inboundGreeting: "Hello! How can I help?",
}
Respostas automáticas usam o sistema de agente. Ajuste com responseModel,
responseSystemPrompt e responseTimeoutMs.
Roteamento por número
Use numbers quando um plugin Voice Call recebe chamadas para vários números de telefone
e cada número deve se comportar como uma linha diferente. Por exemplo, um
número pode usar um assistente pessoal casual enquanto outro usa uma persona
comercial, um agente de resposta diferente e uma voz TTS diferente.
As rotas são selecionadas a partir do número To discado fornecido pelo provedor. As chaves devem ser
números E.164. Quando uma chamada chega, o Voice Call resolve a rota correspondente uma vez,
armazena a rota correspondente no registro da chamada e reutiliza essa configuração efetiva
para a saudação, o caminho clássico de resposta automática, o caminho de consulta em tempo real e a reprodução
TTS. Se nenhuma rota corresponder, a configuração global do Voice Call será usada.
Chamadas de saída não usam numbers; passe o destino de saída, a mensagem e
a sessão explicitamente ao iniciar a chamada.
As substituições de rota atualmente aceitam:
inboundGreetingttsagentIdresponseModelresponseSystemPromptresponseTimeoutMs
O valor de rota tts faz deep merge sobre a configuração global tts do Voice Call, então
geralmente você pode substituir apenas a voz do provedor:
{
inboundGreeting: "Hello from the main line.",
responseSystemPrompt: "You are the default voice assistant.",
tts: {
provider: "openai",
providers: {
openai: { voice: "coral" },
},
},
numbers: {
"+15550001111": {
inboundGreeting: "Silver Fox Cards, how can I help?",
responseSystemPrompt: "You are a concise baseball card specialist.",
tts: {
providers: {
openai: { voice: "alloy" },
},
},
},
},
}
Contrato de saída falada
Para respostas automáticas, o Voice Call anexa um contrato estrito de saída falada ao prompt do sistema:
{"spoken":"..."}
O Voice Call extrai o texto de fala de forma defensiva:
- Ignora payloads marcados como conteúdo de raciocínio/erro.
- Analisa JSON direto, JSON em bloco cercado ou chaves
"spoken"inline. - Retorna para texto simples e remove prováveis parágrafos iniciais de planejamento/metadados.
Isso mantém a reprodução falada focada no texto voltado ao chamador e evita vazar texto de planejamento para o áudio.
Comportamento de início de conversa
Para chamadas conversation de saída, o tratamento da primeira mensagem está vinculado ao estado de reprodução
ao vivo:
- A limpeza da fila por interrupção de fala e a resposta automática são suprimidas somente enquanto a saudação inicial está sendo falada ativamente.
- Se a reprodução inicial falhar, a chamada retorna para
listeninge a mensagem inicial permanece enfileirada para nova tentativa. - A reprodução inicial para streaming do Twilio começa na conexão do stream, sem atraso extra.
- A interrupção por fala aborta a reprodução ativa e limpa entradas TTS do Twilio enfileiradas, mas ainda não reproduzidas. Entradas limpas são resolvidas como ignoradas, para que a lógica de resposta seguinte possa continuar sem aguardar áudio que nunca será reproduzido.
- Conversas de voz em tempo real usam o próprio turno inicial do stream em tempo real. O Voice Call não publica uma atualização TwiML
OPENCLAW_DOCS_MARKER:calloutOpen:U2F5legada para essa mensagem inicial, então sessões<Connect><Stream>de saída permanecem anexadas.
Período de tolerância para desconexão de stream do Twilio
Quando um stream de mídia do Twilio se desconecta, o Voice Call aguarda 2000 ms antes de encerrar automaticamente a chamada:
- Se o stream se reconectar durante essa janela, o encerramento automático será cancelado.
- Se nenhum stream for registrado novamente após o período de tolerância, a chamada será encerrada para evitar chamadas ativas travadas.
Removedor de chamadas obsoletas
Use staleCallReaperSeconds para encerrar chamadas que nunca recebem um
webhook terminal (por exemplo, chamadas em modo de notificação que nunca são concluídas). O padrão
é 0 (desativado).
Intervalos recomendados:
- Produção:
120–300segundos para fluxos do tipo notificação. - Mantenha este valor maior que
maxDurationSecondspara que chamadas normais possam terminar. Um bom ponto de partida émaxDurationSeconds + 30–60segundos.
{
plugins: {
entries: {
"voice-call": {
config: {
maxDurationSeconds: 300,
staleCallReaperSeconds: 360,
},
},
},
},
}
Segurança de Webhook
Quando um proxy ou túnel fica na frente do Gateway, o Plugin reconstrói a URL pública para verificação de assinatura. Estas opções controlam quais cabeçalhos encaminhados são confiáveis:
webhookSecurity.allowedHostsstring[]Permite hosts de cabeçalhos de encaminhamento.
webhookSecurity.trustForwardingHeadersbooleanConfia em cabeçalhos encaminhados sem uma lista de permissões.
webhookSecurity.trustedProxyIPsstring[]Confia em cabeçalhos encaminhados somente quando o IP remoto da solicitação corresponde à lista.
Proteções adicionais:
- A proteção contra repetição de Webhook é habilitada para Twilio e Plivo. Solicitações válidas de Webhook repetidas são confirmadas, mas ignoradas para efeitos colaterais.
- Turnos de conversa do Twilio incluem um token por turno em callbacks de
<Gather>, para que callbacks de fala obsoletos/repetidos não possam satisfazer um turno de transcrição pendente mais novo. - Solicitações de Webhook não autenticadas são rejeitadas antes da leitura do corpo quando os cabeçalhos de assinatura exigidos pelo provedor estão ausentes.
- O Webhook de voice-call usa o perfil de corpo pré-autenticação compartilhado (64 KB / 5 segundos) mais um limite por IP de solicitações em andamento antes da verificação de assinatura.
Exemplo com um host público estável:
{
plugins: {
entries: {
"voice-call": {
config: {
publicUrl: "https://voice.example.com/voice/webhook",
webhookSecurity: {
allowedHosts: ["voice.example.com"],
},
},
},
},
},
}
CLI
openclaw voicecall call --to "+15555550123" --message "Hello from OpenClaw"
openclaw voicecall start --to "+15555550123" # alias for call
openclaw voicecall continue --call-id <id> --message "Any questions?"
openclaw voicecall speak --call-id <id> --message "One moment"
openclaw voicecall dtmf --call-id <id> --digits "ww123456#"
openclaw voicecall end --call-id <id>
openclaw voicecall status --call-id <id>
openclaw voicecall tail
openclaw voicecall latency # summarize turn latency from logs
openclaw voicecall expose --mode funnel
Quando o Gateway já está em execução, comandos operacionais voicecall delegam
ao runtime voice-call pertencente ao Gateway, para que a CLI não vincule um segundo
servidor de Webhook. Se nenhum Gateway estiver acessível, os comandos recorrem a um
runtime de CLI independente.
latency lê calls.jsonl do caminho padrão de armazenamento de voice-call.
Use --file <path> para apontar para um log diferente e --last <n> para limitar
a análise aos últimos N registros (padrão 200). A saída inclui p50/p90/p99
para latência de turno e tempos de espera de escuta.
Ferramenta do agente
Nome da ferramenta: voice_call.
| Ação | Argumentos |
|---|---|
initiate_call |
message, to?, mode?, dtmfSequence? |
continue_call |
callId, message |
speak_to_user |
callId, message |
send_dtmf |
callId, digits |
end_call |
callId |
get_status |
callId |
Este repositório inclui uma documentação de skill correspondente em skills/voice-call/SKILL.md.
RPC do Gateway
| Método | Argumentos |
|---|---|
voicecall.initiate |
to?, message, mode?, dtmfSequence? |
voicecall.continue |
callId, message |
voicecall.speak |
callId, message |
voicecall.dtmf |
callId, digits |
voicecall.end |
callId |
voicecall.status |
callId |
dtmfSequence é válido somente com mode: "conversation". Chamadas em modo notificação
devem usar voicecall.dtmf depois que a chamada existir se precisarem de
dígitos pós-conexão.
Solução de problemas
A configuração falha na exposição do Webhook
Execute a configuração no mesmo ambiente que executa o Gateway:
openclaw voicecall setup
openclaw voicecall setup --json
Para twilio, telnyx e plivo, webhook-exposure deve estar verde. Uma
publicUrl configurada ainda falha quando aponta para espaço de rede local ou privada,
porque a operadora não consegue retornar chamadas para esses endereços. Não use
localhost, 127.0.0.1, 0.0.0.0, 10.x, 172.16.x-172.31.x,
192.168.x, 169.254.x, fc00::/7 ou fd00::/8 como publicUrl.
Chamadas de saída em modo notificação do Twilio enviam seu TwiML OPENCLAW_DOCS_MARKER:calloutOpen:U2F5 inicial diretamente na
solicitação de criação de chamada, então a primeira mensagem falada não depende de o Twilio
buscar o TwiML do Webhook. Um Webhook público ainda é necessário para callbacks de status,
chamadas de conversa, DTMF pré-conexão, streams em tempo real e controle de chamada
pós-conexão.
Use um caminho de exposição pública:
{
plugins: {
entries: {
"voice-call": {
config: {
publicUrl: "https://voice.example.com/voice/webhook",
// or
tunnel: { provider: "ngrok" },
// or
tailscale: { mode: "funnel", path: "/voice/webhook" },
},
},
},
},
}
Após alterar a configuração, reinicie ou recarregue o Gateway e então execute:
openclaw voicecall setup
openclaw voicecall smoke
voicecall smoke é uma simulação, a menos que você passe --yes.
Credenciais do provedor falham
Verifique o provedor selecionado e os campos de credencial exigidos:
- Twilio:
twilio.accountSid,twilio.authTokenefromNumber, ouTWILIO_ACCOUNT_SID,TWILIO_AUTH_TOKENeTWILIO_FROM_NUMBER. - Telnyx:
telnyx.apiKey,telnyx.connectionId,telnyx.publicKeyefromNumber. - Plivo:
plivo.authId,plivo.authTokenefromNumber.
As credenciais devem existir no host do Gateway. Editar um perfil de shell local não afeta um Gateway já em execução até que ele reinicie ou recarregue seu ambiente.
Chamadas iniciam, mas Webhooks do provedor não chegam
Confirme que o console do provedor aponta para a URL pública exata do Webhook:
https://voice.example.com/voice/webhook
Depois inspecione o estado do runtime:
openclaw voicecall status --call-id <id>
openclaw voicecall tail
openclaw logs --follow
Causas comuns:
publicUrlaponta para um caminho diferente deserve.path.- A URL do túnel mudou depois que o Gateway iniciou.
- Um proxy encaminha a solicitação, mas remove ou reescreve cabeçalhos de host/proto.
- Firewall ou DNS roteia o hostname público para algum lugar diferente do Gateway.
- O Gateway foi reiniciado sem o Plugin Voice Call habilitado.
Quando um proxy reverso ou túnel está na frente do Gateway, defina
webhookSecurity.allowedHosts como o hostname público ou use
webhookSecurity.trustedProxyIPs para um endereço de proxy conhecido. Use
webhookSecurity.trustForwardingHeaders somente quando o limite do proxy estiver sob
seu controle.
A verificação de assinatura falha
Assinaturas do provedor são verificadas contra a URL pública que o OpenClaw reconstrói a partir da solicitação recebida. Se as assinaturas falharem:
- Confirme que a URL de Webhook do provedor corresponde exatamente a
publicUrl, incluindo esquema, host e caminho. - Para URLs gratuitas do ngrok, atualize
publicUrlquando o hostname do túnel mudar. - Garanta que o proxy preserve os cabeçalhos originais de host e proto, ou configure
webhookSecurity.allowedHosts. - Não habilite
skipSignatureVerificationfora de testes locais.
Entradas do Google Meet via Twilio falham
O Google Meet usa este Plugin para entradas por discagem do Twilio. Primeiro verifique Voice Call:
openclaw voicecall setup
openclaw voicecall smoke --to "+15555550123"
Depois verifique explicitamente o transporte do Google Meet:
openclaw googlemeet setup --transport twilio
Se Voice Call estiver verde, mas o participante do Meet nunca entrar, verifique o
número de discagem do Meet, o PIN e --dtmf-sequence. A chamada telefônica pode estar saudável enquanto
a reunião rejeita ou ignora uma sequência DTMF incorreta.
O Google Meet inicia a perna telefônica do Twilio por meio de voicecall.start com uma
sequência DTMF pré-conexão. Sequências derivadas de PIN incluem
voiceCall.dtmfDelayMs do Plugin Google Meet como dígitos de espera iniciais do Twilio. O padrão é 12 segundos
porque prompts de discagem do Meet podem chegar tarde. Voice Call então redireciona de volta para
tratamento em tempo real antes que a saudação introdutória seja solicitada.
Use openclaw logs --follow para o rastreamento da fase ao vivo. Uma entrada saudável do Twilio no Meet
registra esta ordem:
- Google Meet delega a entrada via Twilio ao Voice Call.
- Voice Call armazena TwiML DTMF pré-conexão.
- O TwiML inicial do Twilio é consumido e servido antes do tratamento em tempo real.
- Voice Call serve TwiML em tempo real para a chamada Twilio.
- Google Meet solicita fala introdutória com
voicecall.speakapós o atraso pós-DTMF.
openclaw voicecall tail ainda mostra registros de chamadas persistidos; ele é útil para
estado da chamada e transcrições, mas nem toda transição de Webhook/tempo real aparece
ali.
Chamada em tempo real não tem fala
Confirme que apenas um modo de áudio está habilitado. realtime.enabled e
streaming.enabled não podem ambos ser true.
Para chamadas Twilio em tempo real, verifique também:
- Um Plugin provedor em tempo real está carregado e registrado.
realtime.providerestá não definido ou nomeia um provedor registrado.- A chave de API do provedor está disponível para o processo do Gateway.
openclaw logs --followmostra TwiML em tempo real servido, a ponte em tempo real iniciada e a saudação inicial enfileirada.