twilio (Programmable Voice + Media Streams),
telnyx (Call Control v2), plivo (Voice API + XML transfer + GetInput
speech), mock (разработка/без сети).
Plugin Voice Call работает внутри процесса Gateway. Если вы используете
удаленный Gateway, установите и настройте Plugin на машине, где запущен
Gateway, затем перезапустите Gateway, чтобы загрузить его.
Быстрый старт
Установите Plugin
- Из npm
- Из локальной папки (разработка)
Настройте провайдера и Webhook
Задайте конфигурацию в
plugins.entries.voice-call.config (полную форму см.
в разделе Конфигурация ниже). Минимум:
provider, учетные данные провайдера, fromNumber и публично
доступный URL Webhook.Проверьте настройку
streaming или realtime). Используйте
--json для скриптов.Конфигурация
Еслиenabled: true, но у выбранного провайдера отсутствуют учетные данные,
при запуске Gateway записывает предупреждение о незавершенной настройке с отсутствующими ключами и
пропускает запуск runtime. Команды, RPC-вызовы и инструменты агента при использовании все равно
возвращают точную отсутствующую конфигурацию провайдера.
Учетные данные voice-call принимают SecretRefs.
plugins.entries.voice-call.config.twilio.authToken, plugins.entries.voice-call.config.realtime.providers.*.apiKey, plugins.entries.voice-call.config.streaming.providers.*.apiKey и plugins.entries.voice-call.config.tts.providers.*.apiKey разрешаются через стандартную поверхность SecretRef; см. поверхность учетных данных SecretRef.Примечания по доступности провайдеров и безопасности
Примечания по доступности провайдеров и безопасности
- Twilio, Telnyx и Plivo всем требуется публично доступный URL Webhook.
mock— локальный провайдер для разработки (без сетевых вызовов).- Telnyx требует
telnyx.publicKey(илиTELNYX_PUBLIC_KEY), еслиskipSignatureVerificationне равен true. skipSignatureVerificationпредназначен только для локального тестирования.- На бесплатном уровне ngrok задайте
publicUrlравным точному URL ngrok; проверка подписи всегда применяется. tunnel.allowNgrokFreeTierLoopbackBypass: trueразрешает Webhook Twilio с недействительными подписями только когдаtunnel.provider="ngrok"иserve.bindявляется loopback (локальный агент ngrok). Только для локальной разработки.- URL бесплатного уровня Ngrok могут меняться или добавлять промежуточное поведение; если
publicUrlменяется, подписи Twilio перестают проходить. Production: предпочтите стабильный домен или Tailscale funnel.
Лимиты потоковых подключений
Лимиты потоковых подключений
streaming.preStartTimeoutMsзакрывает сокеты, которые никогда не отправляют допустимый кадрstart.streaming.maxPendingConnectionsограничивает общее число неаутентифицированных pre-start-сокетов.streaming.maxPendingConnectionsPerIpограничивает неаутентифицированные pre-start-сокеты на исходный IP.streaming.maxConnectionsограничивает общее число открытых сокетов медиапотока (pending + active).
Миграции устаревшей конфигурации
Миграции устаревшей конфигурации
Старые конфигурации, использующие
provider: "log", twilio.from или устаревшие
ключи OpenAI streaming.*, переписываются командой openclaw doctor --fix.
Runtime fallback пока все еще принимает старые ключи voice-call, но
путь переписывания — openclaw doctor --fix, а compat-прослойка
временная.Автоматически мигрируемые ключи streaming:streaming.sttProvider→streaming.providerstreaming.openaiApiKey→streaming.providers.openai.apiKeystreaming.sttModel→streaming.providers.openai.modelstreaming.silenceDurationMs→streaming.providers.openai.silenceDurationMsstreaming.vadThreshold→streaming.providers.openai.vadThreshold
Область сеанса
По умолчанию Voice Call используетsessionScope: "per-phone", поэтому повторные вызовы от
одного и того же вызывающего сохраняют память разговора. Задайте sessionScope: "per-call", когда
каждый операторский вызов должен начинаться со свежим контекстом, например для ресепшена,
бронирования, IVR или мостов Google Meet, где один и тот же номер телефона может
представлять разные встречи.
Voice Call хранит сгенерированные ключи сеансов в настроенном пространстве имен агента
(agent:<agentId>:voice:*), чтобы память вызовов переживала каноникализацию session-key в Gateway
после перезапусков. Явные сырые ключи интеграций используют то же
пространство имен агента. Канонический ключ agent:<configuredAgentId>:* сохраняет этого владельца,
а его основные alias учитывают core session.mainKey и глобальную область. Чужой или
некорректный ввод agent:* помещается как opaque-ключ в область настроенного агента;
global и unknown остаются глобальными sentinel-значениями. При запуске Gateway продвигает старые
сырые ключи в хранилищах по умолчанию или с шаблоном {agentId}, если путь доказывает одного
владельца. В фиксированных пользовательских хранилищах неоднозначные устаревшие строки остаются без изменений, потому что
в них недостаточно информации для выбора владельца; новые вызовы используют
каноническую историю в области агента.
Голосовые разговоры в реальном времени
realtime выбирает полнодуплексного провайдера голоса в реальном времени для live-аудио
вызова. Он отделен от streaming, который только пересылает аудио
провайдерам транскрипции в реальном времени.
Текущее поведение runtime:
realtime.enabledподдерживается для Twilio Media Streams.realtime.providerнеобязателен. Если он не задан, Voice Call использует первого зарегистрированного провайдера голоса в реальном времени.- Встроенные провайдеры голоса в реальном времени: Google Gemini Live (
google) и OpenAI (openai), регистрируемые их provider-Plugin. - Сырая конфигурация, принадлежащая провайдеру, находится в
realtime.providers.<providerId>. - Voice Call по умолчанию предоставляет общий инструмент реального времени
openclaw_agent_consult. Модель реального времени может вызывать его, когда вызывающий просит более глубокое рассуждение, актуальную информацию или обычные инструменты OpenClaw. realtime.consultPolicyнеобязательно добавляет указания о том, когда модель реального времени должна вызыватьopenclaw_agent_consult.realtime.agentContext.enabledпо умолчанию выключен. Когда он включен, Voice Call внедряет ограниченную идентичность агента и выбранную капсулу workspace-file в инструкции провайдера реального времени при настройке сеанса.realtime.fastContext.enabledпо умолчанию выключен. Когда он включен, Voice Call сначала ищет в индексированной памяти/контексте сеанса вопрос для consult и возвращает эти фрагменты модели реального времени в пределахrealtime.fastContext.timeoutMs, прежде чем перейти к полному consult-агенту только еслиrealtime.fastContext.fallbackToConsultравен true.- Если
realtime.providerуказывает на незарегистрированного провайдера или если вообще не зарегистрирован ни один провайдер голоса в реальном времени, Voice Call записывает предупреждение и пропускает realtime-медиа вместо того, чтобы завершить весь Plugin ошибкой. - Ключи consult-сеанса повторно используют сохраненный сеанс вызова, когда он доступен, затем переходят к настроенному
sessionScope(per-phoneпо умолчанию илиper-callдля изолированных вызовов).
Политика инструментов
realtime.toolPolicy управляет запуском consult:
| Политика | Поведение |
|---|---|
safe-read-only | Предоставляет инструмент consult и ограничивает обычного агента инструментами read, web_search, web_fetch, x_search, memory_search и memory_get. |
owner | Предоставляет инструмент consult и позволяет обычному агенту использовать нормальную политику инструментов агента. |
none | Не предоставляет инструмент consult. Пользовательские realtime.tools все равно передаются провайдеру реального времени. |
realtime.consultPolicy управляет только инструкциями модели реального времени:
| Политика | Указания |
|---|---|
auto | Сохранять prompt по умолчанию и позволить провайдеру решать, когда вызывать инструмент consult. |
substantive | Отвечать на простые conversational glue напрямую и выполнять consult перед фактами, памятью, инструментами или контекстом. |
always | Выполнять consult перед каждым содержательным ответом. |
Голосовой контекст агента
Включайтеrealtime.agentContext, когда голосовой мост должен звучать как
настроенный агент OpenClaw без полной задержки обращения к агенту на
обычных ходах. Капсула контекста добавляется один раз при создании
сеанса реального времени, поэтому она не добавляет задержку на каждый ход.
Вызовы openclaw_agent_consult по-прежнему запускают полного агента
OpenClaw и должны использоваться для работы с инструментами, актуальной
информации, поиска в памяти или состояния рабочей области.
Примеры провайдеров реального времени
- Google Gemini Live
- OpenAI
Значения по умолчанию: ключ API из
realtime.providers.google.apiKey,
GEMINI_API_KEY или GOOGLE_GENERATIVE_AI_API_KEY; модель
gemini-2.5-flash-native-audio-preview-12-2025; голос Kore.
sessionResumption и contextWindowCompression по умолчанию включены
для более долгих вызовов с возможностью переподключения. Используйте
silenceDurationMs, startSensitivity и endSensitivity, чтобы
настроить более быстрое чередование реплик в телефонном аудио.Потоковая транскрибация
streaming выбирает провайдера транскрибации в реальном времени для
аудио живого вызова.
Текущее поведение среды выполнения:
streaming.providerнеобязателен. Если он не задан, Voice Call использует первого зарегистрированного провайдера транскрибации в реальном времени.- Встроенные провайдеры транскрибации в реальном времени: Deepgram (
deepgram), ElevenLabs (elevenlabs), Mistral (mistral), OpenAI (openai) и xAI (xai), зарегистрированные их плагинами провайдеров. - Необработанная конфигурация, принадлежащая провайдеру, находится в
streaming.providers.<providerId>. - После того как Twilio отправляет принятое сообщение
startдля потока, Voice Call немедленно регистрирует поток, ставит входящее медиа в очередь через провайдера транскрибации, пока провайдер подключается, и запускает начальное приветствие только после готовности транскрибации в реальном времени. - Если
streaming.providerуказывает на незарегистрированного провайдера или ни один провайдер не зарегистрирован, Voice Call записывает предупреждение в журнал и пропускает потоковую передачу медиа вместо сбоя всего плагина.
Примеры потоковых провайдеров
- OpenAI
- xAI
Значения по умолчанию: ключ API
streaming.providers.openai.apiKey или
OPENAI_API_KEY; модель gpt-4o-transcribe; silenceDurationMs: 800;
vadThreshold: 0.5.TTS для вызовов
Voice Call использует базовую конфигурациюmessages.tts для потоковой
речи в вызовах. Вы можете переопределить ее в конфигурации плагина с
той же структурой — она глубоко объединяется с messages.tts.
- Устаревшие ключи
tts.<provider>внутри конфигурации плагина (openai,elevenlabs,microsoft,edge) исправляются командойopenclaw doctor --fix; зафиксированная конфигурация должна использоватьtts.providers.<provider>. - Core TTS используется, когда включена потоковая передача медиа Twilio; в противном случае вызовы возвращаются к нативным голосам провайдера.
- Если поток медиа Twilio уже активен, Voice Call не возвращается к TwiML
<Say>. Если телефонный TTS недоступен в этом состоянии, запрос воспроизведения завершается ошибкой вместо смешивания двух путей воспроизведения. - Когда телефонный TTS возвращается к вторичному провайдеру, Voice Call записывает предупреждение с цепочкой провайдеров (
from,to,attempts) для отладки. - Когда barge-in Twilio или демонтаж потока очищает ожидающую очередь TTS, поставленные в очередь запросы воспроизведения завершаются вместо того, чтобы оставлять вызывающих абонентов в ожидании завершения воспроизведения.
Примеры TTS
- Core TTS only
- Override to ElevenLabs (calls only)
- OpenAI model override (deep-merge)
Входящие вызовы
Политика входящих вызовов по умолчанию —disabled. Чтобы включить входящие
вызовы, задайте:
responseModel, responseSystemPrompt и responseTimeoutMs.
Маршрутизация по номерам
Используйтеnumbers, когда один плагин Voice Call принимает вызовы для
нескольких телефонных номеров и каждый номер должен вести себя как отдельная
линия. Например, один номер может использовать непринужденного личного
ассистента, а другой — деловую персону, другого агента ответа и другой голос
TTS.
Маршруты выбираются по предоставленному провайдером набранному номеру To.
Ключи должны быть номерами E.164. Когда вызов поступает, Voice Call один раз
разрешает соответствующий маршрут, сохраняет сопоставленный маршрут в записи
вызова и повторно использует эту эффективную конфигурацию для приветствия,
классического пути автоответа, пути консультации в реальном времени и
воспроизведения TTS. Если маршрут не совпадает, используется глобальная
конфигурация Voice Call. Исходящие вызовы не используют numbers; передавайте
исходящую цель, сообщение и сеанс явно при инициировании вызова.
Переопределения маршрутов сейчас поддерживают:
inboundGreetingttsagentIdresponseModelresponseSystemPromptresponseTimeoutMs
tts глубоко объединяется поверх глобальной конфигурации
Voice Call tts, поэтому обычно можно переопределить только голос провайдера:
Контракт речевого вывода
Для автоответов Voice Call добавляет строгий контракт речевого вывода к системной подсказке:- Игнорирует полезные нагрузки, помеченные как содержимое рассуждения или ошибки.
- Разбирает прямой JSON, JSON в огражденном блоке или встроенные ключи
"spoken". - Возвращается к обычному тексту и удаляет вероятные вступительные абзацы планирования или метаданных.
Поведение запуска разговора
Для исходящих вызововconversation обработка первого сообщения привязана к
живому состоянию воспроизведения:
- Очистка очереди barge-in и автоответ подавляются только пока начальное приветствие активно произносится.
- Если начальное воспроизведение завершается ошибкой, вызов возвращается в состояние
listening, а начальное сообщение остается в очереди для повторной попытки. - Начальное воспроизведение для потоковой передачи Twilio запускается при подключении потока без дополнительной задержки.
- Barge-in прерывает активное воспроизведение и очищает поставленные в очередь, но еще не воспроизводимые записи Twilio TTS. Очищенные записи разрешаются как пропущенные, поэтому логика последующего ответа может продолжаться без ожидания аудио, которое никогда не будет воспроизведено.
- Голосовые разговоры в реальном времени используют собственный начальный ход потока реального времени. Voice Call не отправляет устаревшее обновление TwiML
<Say>для этого начального сообщения, поэтому исходящие сеансы<Connect><Stream>остаются подключенными.
Льготный период при отключении потока Twilio
Когда медиапоток Twilio отключается, Voice Call ждет 2000 мс перед автоматическим завершением вызова:- Если поток повторно подключается в течение этого окна, автоматическое завершение отменяется.
- Если после льготного периода ни один поток не регистрируется повторно, вызов завершается, чтобы предотвратить зависшие активные вызовы.
Очистка устаревших вызовов
ИспользуйтеstaleCallReaperSeconds, чтобы завершать вызовы, которые так и не получают
завершающий Webhook (например, вызовы в режиме уведомления, которые никогда не завершаются). Значение по умолчанию
— 0 (отключено).
Рекомендуемые диапазоны:
- Production:
120–300секунд для потоков в стиле уведомлений. - Держите это значение выше, чем
maxDurationSeconds, чтобы обычные вызовы могли завершиться. Хорошая отправная точка —maxDurationSeconds + 30–60секунд.
Безопасность Webhook
Когда перед Gateway стоит прокси или туннель, Plugin восстанавливает публичный URL для проверки подписи. Эти параметры управляют тем, каким forwarded-заголовкам можно доверять:Список разрешенных хостов из forwarding-заголовков.
Доверять forwarded-заголовкам без списка разрешенных хостов.
Доверять forwarded-заголовкам только тогда, когда удаленный IP запроса совпадает со списком.
- Защита от повторного воспроизведения Webhook включена для Twilio и Plivo. Повторно воспроизведенные валидные Webhook-запросы подтверждаются, но пропускаются для побочных эффектов.
- Ходы разговора Twilio включают токен для каждого хода в обратных вызовах
<Gather>, поэтому устаревшие или повторно воспроизведенные речевые обратные вызовы не могут удовлетворить более новый ожидающий ход транскрипта. - Неаутентифицированные Webhook-запросы отклоняются до чтения тела, если отсутствуют обязательные заголовки подписи провайдера.
- Webhook voice-call использует общий pre-auth профиль тела (64 КБ / 5 секунд) плюс ограничение на количество одновременных запросов по IP перед проверкой подписи.
CLI
voicecall делегируются
runtime voice-call, которым владеет Gateway, поэтому CLI не привязывает второй
Webhook-сервер. Если Gateway недоступен, команды переключаются на
автономный runtime CLI.
latency читает calls.jsonl из стандартного пути хранилища voice-call.
Используйте --file <path>, чтобы указать другой журнал, и --last <n>, чтобы ограничить
анализ последними N записями (по умолчанию 200). Вывод включает p50/p90/p99
для задержки хода и времени ожидания прослушивания.
Инструмент агента
Имя инструмента:voice_call.
| Действие | Аргументы |
|---|---|
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 |
Gateway RPC
| Метод | Аргументы |
|---|---|
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 допустим только с mode: "conversation". Вызовы в режиме уведомления
должны использовать voicecall.dtmf после создания вызова, если им нужны
цифры после соединения.
Устранение неполадок
Настройка не может открыть Webhook наружу
Запускайте настройку из той же среды, где работает Gateway:twilio, telnyx и plivo проверка webhook-exposure должна быть зеленой. Настроенный
publicUrl все равно не пройдет проверку, если указывает на локальное или частное сетевое
пространство, потому что оператор не сможет выполнить обратный вызов на эти адреса. Не используйте
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 или fd00::/8 как publicUrl.
Исходящие вызовы Twilio в режиме уведомления отправляют начальный TwiML <Say> напрямую в
запросе создания вызова, поэтому первое произнесенное сообщение не зависит от того,
получит ли Twilio Webhook TwiML. Публичный Webhook по-прежнему требуется для status callbacks,
разговорных вызовов, pre-connect DTMF, realtime-потоков и управления вызовом
после соединения.
Используйте один публичный путь доступа:
voicecall smoke — это пробный запуск, если вы не передали --yes.
Учетные данные провайдера не проходят проверку
Проверьте выбранного провайдера и обязательные поля учетных данных:- Twilio:
twilio.accountSid,twilio.authTokenиfromNumber, илиTWILIO_ACCOUNT_SID,TWILIO_AUTH_TOKENиTWILIO_FROM_NUMBER. - Telnyx:
telnyx.apiKey,telnyx.connectionId,telnyx.publicKeyиfromNumber. - Plivo:
plivo.authId,plivo.authTokenиfromNumber.
Вызовы запускаются, но Webhook провайдера не приходят
Убедитесь, что консоль провайдера указывает на точный публичный URL Webhook:publicUrlуказывает на путь, отличный отserve.path.- URL туннеля изменился после запуска Gateway.
- Прокси пересылает запрос, но удаляет или переписывает заголовки host/proto.
- Firewall или DNS направляет публичное имя хоста куда-то помимо Gateway.
- Gateway был перезапущен без включенного Plugin Voice Call.
webhookSecurity.allowedHosts равным публичному имени хоста или используйте
webhookSecurity.trustedProxyIPs для известного адреса прокси. Используйте
webhookSecurity.trustForwardingHeaders только тогда, когда граница прокси находится под
вашим контролем.
Проверка подписи не проходит
Подписи провайдера проверяются относительно публичного URL, который OpenClaw восстанавливает из входящего запроса. Если подписи не проходят проверку:- Убедитесь, что URL Webhook у провайдера точно совпадает с
publicUrl, включая схему, хост и путь. - Для URL ngrok free-tier обновляйте
publicUrl, когда имя хоста туннеля меняется. - Убедитесь, что прокси сохраняет исходные заголовки host и proto, или настройте
webhookSecurity.allowedHosts. - Не включайте
skipSignatureVerificationвне локального тестирования.
Не удается присоединиться к Google Meet через Twilio
Google Meet использует этот Plugin для подключений через Twilio dial-in. Сначала проверьте Voice Call:--dtmf-sequence. Телефонный вызов может быть исправен, пока
встреча отклоняет или игнорирует неверную последовательность DTMF.
Google Meet запускает телефонную ветку Twilio через voicecall.start с
pre-connect последовательностью DTMF. Последовательности, полученные из PIN, включают
voiceCall.dtmfDelayMs Plugin Google Meet как начальные цифры ожидания Twilio. Значение по умолчанию — 12 секунд,
поскольку подсказки dial-in Meet могут приходить поздно. Затем Voice Call перенаправляет обратно на
realtime-обработку до запроса вступительного приветствия.
Используйте openclaw logs --follow для трассировки живой фазы. Успешное присоединение Twilio Meet
записывает в журнал следующий порядок:
- Google Meet делегирует присоединение Twilio в Voice Call.
- Voice Call сохраняет pre-connect DTMF TwiML.
- Начальный TwiML Twilio потребляется и отдается до realtime-обработки.
- Voice Call отдает realtime TwiML для вызова Twilio.
- Google Meet запрашивает вступительную речь через
voicecall.speakпосле задержки post-DTMF.
openclaw voicecall tail по-прежнему показывает сохраненные записи вызовов; это полезно для
состояния вызова и транскриптов, но не каждый Webhook или realtime-переход появляется
там.
В realtime-вызове нет речи
Убедитесь, что включен только один аудиорежим.realtime.enabled и
streaming.enabled не могут одновременно быть true.
Для realtime-вызовов Twilio также проверьте:
- Plugin realtime-провайдера загружен и зарегистрирован.
realtime.providerне задан или указывает на зарегистрированного провайдера.- API-ключ провайдера доступен процессу Gateway.
openclaw logs --followпоказывает, что realtime TwiML отдан, realtime-мост запущен, а начальное приветствие поставлено в очередь.