Plugin guides
Плагин голосовых вызовов
Голосовые вызовы для OpenClaw через плагин: исходящие уведомления, многоходовые диалоги, полнодуплексная голосовая связь в реальном времени, потоковая транскрипция и входящие вызовы с политиками списков разрешений.
Провайдеры: mock (для разработки, без сети), plivo (Voice API + передача XML +
распознавание речи GetInput), telnyx (Call Control v2), twilio (Programmable Voice +
Media Streams).
Быстрый старт
Установите плагин
Из npm
openclaw plugins install @openclaw/voice-callИз локальной папки (для разработки)
PLUGIN_SRC=./path/to/local/voice-call-pluginopenclaw plugins install "$PLUGIN_SRC"cd "$PLUGIN_SRC" && pnpm installИспользуйте пакет без указания версии, чтобы следовать текущему тегу выпуска. Закрепляйте точную версию только тогда, когда требуется воспроизводимая установка. После этого перезапустите Gateway, чтобы плагин загрузился.
Настройте провайдера и Webhook
Задайте конфигурацию в plugins.entries.voice-call.config (см. раздел
Конфигурация ниже). Необходимый минимум: provider, учётные данные
провайдера, fromNumber и общедоступный URL-адрес Webhook.
Проверьте настройку
openclaw voicecall setupopenclaw voicecall setup --jsonПроверяет, включён ли плагин, учётные данные провайдера, доступность Webhook и
активен ли только один аудиорежим (streaming или realtime).
Выполните быструю проверку
openclaw voicecall smokeopenclaw voicecall smoke --to "+15555550123"По умолчанию обе команды выполняются в тестовом режиме без реального вызова. Добавьте --yes, чтобы совершить короткий исходящий
вызов с уведомлением:
openclaw voicecall smoke --to "+15555550123" --yesКонфигурация
Если enabled: true, но у выбранного провайдера отсутствуют учётные данные, при запуске Gateway
в журнал записывается предупреждение о незавершённой настройке с перечислением отсутствующих ключей, а
среда выполнения не запускается. При использовании команд, вызовов RPC и инструментов агента они по-прежнему возвращают
точный список отсутствующих параметров конфигурации.
{ 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: { speakerVoice: "alloy" }, }, }, }, }, twilio: { accountSid: "ACxxxxxxxx", authToken: "...", // region: "ie1", // optional: us1 | ie1 | au1; defaults to us1 }, 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 /* Twilio only; see Streaming transcription */ }, realtime: { enabled: false /* see Realtime voice conversations */ }, }, }, }, },}Справочник по конфигурации
Ключи верхнего уровня в plugins.entries.voice-call.config, не показанные выше:
| Ключ | Значение по умолчанию | Примечания |
|---|---|---|
enabled |
false |
Главный переключатель включения и выключения. |
inboundPolicy |
"disabled" |
disabled | allowlist | pairing | open. См. Входящие вызовы. |
allowFrom |
[] |
Список разрешений E.164 для inboundPolicy: "allowlist". |
maxDurationSeconds |
300 |
Жёсткое ограничение длительности каждого вызова, применяемое независимо от состояния ответа. |
staleCallReaperSeconds |
120 |
См. Очистка устаревших вызовов. 0 отключает её. |
silenceTimeoutMs |
800 |
Определение тишины в конце речи для классического режима (не в реальном времени). |
transcriptTimeoutMs |
180000 |
Максимальное время ожидания транскрипции речи звонящего перед прекращением обработки хода. |
ringTimeoutMs |
30000 |
Время ожидания ответа для исходящих вызовов. |
maxConcurrentCalls |
1 |
Исходящие вызовы сверх этого ограничения отклоняются. |
outbound.notifyHangupDelaySec |
3 |
Число секунд ожидания после TTS перед автоматическим завершением вызова в режиме уведомления. |
skipSignatureVerification |
false |
Только для локального тестирования; никогда не включайте в рабочей среде. |
store |
не задано | Переопределяет стандартный путь журнала вызовов ~/.openclaw/voice-calls. |
agentId |
"main" |
Агент, используемый для генерации ответов и хранения сеансов. |
responseModel |
не задано | Переопределяет стандартную модель для классических ответов (не в реальном времени). |
responseSystemPrompt |
генерируется | Пользовательская системная инструкция для классических ответов. |
responseTimeoutMs |
30000 |
Время ожидания генерации классического ответа (мс). |
По умолчанию Twilio использует конечную точку REST для US1. Чтобы обрабатывать вызовы в поддерживаемом
регионе за пределами США, задайте для twilio.region значение ie1 или au1 и используйте учётные данные из
этого региона. См.
руководство Twilio по использованию REST API в регионах за пределами США.
Примечания о доступности и безопасности провайдеров
- Для 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 завершится ошибкой. Для рабочей среды предпочтительнее стабильный домен или туннель Tailscale.
Ограничения потоковых подключений
streaming.preStartTimeoutMs(по умолчанию5000) закрывает сокеты, которые так и не отправили допустимый кадрstart.streaming.maxPendingConnections(по умолчанию32) ограничивает общее количество неаутентифицированных сокетов до начала сеанса.streaming.maxPendingConnectionsPerIp(по умолчанию4) ограничивает количество неаутентифицированных сокетов до начала сеанса для каждого IP-адреса источника.streaming.maxConnections(по умолчанию128) ограничивает общее количество открытых сокетов медиапотоков (ожидающих и активных).
Миграции устаревшей конфигурации
При разборе конфигурации эти устаревшие ключи автоматически нормализуются, а в журнал
записывается предупреждение с путём замены; совместимый переходный слой будет удалён в будущем
выпуске (2026.6.0), поэтому запустите openclaw doctor --fix, чтобы преобразовать сохранённую
конфигурацию в каноническую форму:
provider: "log"→provider: "mock"twilio.from→fromNumberstreaming.sttProvider→streaming.providerstreaming.openaiApiKey→streaming.providers.openai.apiKeystreaming.sttModel→streaming.providers.openai.modelstreaming.silenceDurationMs→streaming.providers.openai.silenceDurationMsstreaming.vadThreshold→streaming.providers.openai.vadThresholdrealtime.agentContext.includeSystemPromptудалён (контекст реального времени теперь использует сгенерированную инструкцию агента)
Область действия сеанса
По умолчанию плагин голосовых вызовов использует sessionScope: "per-phone", поэтому повторные вызовы от
одного и того же звонящего сохраняют память диалога. Задайте sessionScope: "per-call", если
каждый вызов через оператора должен начинаться с нового контекста, например для службы приёма,
бронирования, IVR или подключения к Google Meet, где один и тот же номер телефона может
соответствовать разным встречам.
Плагин голосовых вызовов сохраняет сгенерированные ключи сеансов в пространстве имён настроенного агента
(agent:<agentId>:voice:*). Явно заданные необработанные ключи интеграции разрешаются в
том же пространстве имён: канонический ключ agent:<configuredAgentId>:* сохраняет этого
владельца и учитывает псевдонимы основного session.mainKey/глобальной области; сторонний или
некорректный ввод agent:* помещается в область настроенного агента как непрозрачный ключ;
global и unknown остаются глобальными сигнальными значениями.
Голосовые диалоги в реальном времени
realtime выбирает провайдера полнодуплексной голосовой связи в реальном времени для звука активного вызова.
Он не связан с streaming, который только перенаправляет звук провайдерам
транскрипции в реальном времени.
Текущее поведение среды выполнения:
realtime.enabledподдерживается для Twilio и Telnyx.realtime.providerявляется необязательным. Если значение не задано, Voice Call использует первого зарегистрированного провайдера голосовой связи в реальном времени.- Встроенные провайдеры голосовой связи в реальном времени: Google Gemini Live (
google) и OpenAI (openai), зарегистрированные соответствующими плагинами провайдеров. - Необработанная конфигурация, принадлежащая провайдеру, находится в
realtime.providers.<providerId>. - По умолчанию Voice Call предоставляет общий инструмент реального времени
openclaw_agent_consult. Модель реального времени может вызывать его, когда абонент просит провести более глубокий анализ, получить актуальную информацию или использовать обычные инструменты OpenClaw. realtime.consultPolicyпри необходимости добавляет указания о том, когда модель реального времени должна вызыватьopenclaw_agent_consult.realtime.agentContext.enabledпо умолчанию отключён. Если он включён, при настройке сеанса Voice Call добавляет в инструкции провайдера реального времени ограниченный контекст с идентичностью агента и выбранными файлами рабочего пространства.realtime.fastContext.enabledпо умолчанию отключён. Если он включён, Voice Call сначала ищет вопрос консультации в индексированном контексте памяти и сеанса и возвращает найденные фрагменты модели реального времени в пределахrealtime.fastContext.timeoutMs, а затем обращается к полноценному агенту консультации, только еслиrealtime.fastContext.fallbackToConsultимеет значение true.- Если
realtime.providerуказывает на незарегистрированного провайдера или ни один провайдер голосовой связи в реальном времени вообще не зарегистрирован, Voice Call записывает предупреждение в журнал и пропускает обработку мультимедиа в реальном времени вместо завершения всего плагина с ошибкой. inboundPolicyне должен иметь значение"disabled", когдаrealtime.enabledимеет значение true;validateProviderConfigотклоняет такое сочетание.- Ключи сеанса консультации при наличии повторно используют сохранённый сеанс вызова, а иначе используют настроенный
sessionScope(по умолчаниюper-phoneилиper-callдля изолированных вызовов).
Политика инструментов
realtime.toolPolicy управляет запуском консультации:
| Политика | Поведение |
|---|---|
safe-read-only |
Предоставить инструмент консультации и ограничить обычного агента инструментами read, web_search, web_fetch, x_search, memory_search и memory_get. |
owner |
Предоставить инструмент консультации и разрешить обычному агенту использовать стандартную политику инструментов агента. |
none |
Не предоставлять инструмент консультации. Пользовательские realtime.tools по-прежнему передаются провайдеру реального времени. |
realtime.consultPolicy управляет только инструкциями модели реального времени:
| Политика | Указания |
|---|---|
auto |
Сохранить стандартный промпт и позволить провайдеру решать, когда вызывать инструмент консультации. |
substantive |
Отвечать напрямую на простые связующие реплики в диалоге и обращаться за консультацией перед ответами, требующими фактов, памяти, инструментов или контекста. |
always |
Обращаться за консультацией перед каждым содержательным ответом. |
Голосовой контекст агента
Включите realtime.agentContext, если голосовой шлюз должен звучать как
настроенный агент OpenClaw без полного цикла обращения к агенту за консультацией
для обычных реплик. Контекстный пакет добавляется один раз при создании сеанса
реального времени, поэтому он не увеличивает задержку для каждой реплики. Вызовы
openclaw_agent_consult по-прежнему запускают полноценного агента OpenClaw и должны использоваться
для работы с инструментами, получения актуальной информации, поиска в памяти или состояния рабочего пространства.
{ 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, includeWorkspaceFiles: true, files: ["SOUL.md", "IDENTITY.md", "USER.md"], }, }, }, }, }, },}Примеры провайдеров реального времени
Google Gemini Live
Значения по умолчанию: ключ API из realtime.providers.google.apiKey, GEMINI_API_KEY
или GOOGLE_API_KEY; модель gemini-3.1-flash-live-preview;
голос Kore. sessionResumption и contextWindowCompression по умолчанию включены
для более длительных вызовов с возможностью переподключения. Используйте silenceDurationMs,
startSensitivity и endSensitivity, чтобы настроить более быструю смену реплик
для телефонного аудио.
{ plugins: { entries: { "voice-call": { config: { provider: "twilio", inboundPolicy: "allowlist", allowFrom: ["+15550005678"], realtime: { enabled: true, provider: "google", instructions: "Говорите кратко. Вызывайте openclaw_agent_consult перед использованием более сложных инструментов.", toolPolicy: "safe-read-only", consultPolicy: "substantive", consultThinkingLevel: "low", consultFastMode: true, agentContext: { enabled: true }, providers: { google: { apiKey: "${GEMINI_API_KEY}", model: "gemini-3.1-flash-live-preview", speakerVoice: "Kore", silenceDurationMs: 500, startSensitivity: "high", }, }, }, }, }, }, },}OpenAI
{ plugins: { entries: { "voice-call": { config: { realtime: { enabled: true, provider: "openai", providers: { openai: { apiKey: "${OPENAI_API_KEY}" }, }, }, }, }, }, },}См. разделы Провайдер Google и Провайдер OpenAI, посвящённые параметрам голосовой связи в реальном времени для конкретных провайдеров.
Потоковая транскрипция
streaming подключает Twilio Media Streams к провайдеру транскрипции в реальном времени.
Для классического потокового пути требуется provider: "twilio"; конфигурация с
Telnyx, Plivo или mock отклоняется. Для передачи аудио Telnyx в реальном времени вместо этого используется
отдельно аутентифицируемый путь realtime.enabled.
Текущее поведение среды выполнения:
streaming.providerявляется необязательным. Если значение не задано, Voice Call использует первого зарегистрированного провайдера транскрипции в реальном времени.- Встроенные провайдеры транскрипции в реальном времени: Deepgram (
deepgram), ElevenLabs (elevenlabs), Mistral (mistral), OpenAI (openai) и xAI (xai), зарегистрированные соответствующими плагинами провайдеров. - Необработанная конфигурация, принадлежащая провайдеру, находится в
streaming.providers.<providerId>. - После получения от Twilio принятого сообщения потока
startVoice Call немедленно регистрирует поток, ставит входящие мультимедийные данные в очередь для обработки провайдером транскрипции, пока тот подключается, и запускает начальное приветствие только после готовности транскрипции в реальном времени. - Если
streaming.providerуказывает на незарегистрированного провайдера или ни один провайдер не зарегистрирован, Voice Call записывает предупреждение в журнал и пропускает потоковую передачу мультимедиа вместо завершения всего плагина с ошибкой.
Примеры потоковых провайдеров
OpenAI
Значения по умолчанию: ключ API streaming.providers.openai.apiKey или
OPENAI_API_KEY; модель 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-...", // необязательно, если задан OPENAI_API_KEY model: "gpt-4o-transcribe", silenceDurationMs: 800, vadThreshold: 0.5, }, }, }, }, }, }, },}xAI
Значения по умолчанию: ключ API streaming.providers.xai.apiKey или XAI_API_KEY (если
ни один не задан, используется профиль аутентификации xAI OAuth); конечная точка
wss://api.x.ai/v1/stt; кодировка mulaw; частота дискретизации 8000;
endpointingMs: 800; interimResults: true.
{ plugins: { entries: { "voice-call": { config: { streaming: { enabled: true, provider: "xai", streamPath: "/voice/stream", providers: { xai: { apiKey: "${XAI_API_KEY}", // необязательно, если задан XAI_API_KEY endpointingMs: 800, language: "en", }, }, }, }, }, }, },}TTS для вызовов
Voice Call использует основную конфигурацию messages.tts для потокового синтеза речи во время
вызовов. Её можно переопределить в конфигурации плагина, используя ту же структуру —
она глубоко объединяется с messages.tts.
{ tts: { provider: "elevenlabs", providers: { elevenlabs: { speakerVoiceId: "pMsXgVXv3BLzUgSXRplE", modelId: "eleven_multilingual_v2", }, }, },}Примечания о поведении:
- Устаревшие ключи
tts.<provider>в конфигурации плагина (openai,elevenlabs,microsoft,edge) исправляются командойopenclaw doctor --fix; в сохраняемой конфигурации следует использоватьtts.providers.<provider>. - Основной TTS используется, когда включена потоковая передача мультимедиа Twilio; в противном случае для вызовов используются встроенные голоса провайдера.
- Если поток мультимедиа Twilio уже активен, Voice Call не переключается на резервный вариант TwiML
OPENCLAW_DOCS_MARKER:calloutOpen:U2F5. Если в этом состоянии телефонный TTS недоступен, запрос воспроизведения завершается с ошибкой вместо смешивания двух путей воспроизведения. - Когда телефонный TTS переключается на резервного провайдера, Voice Call записывает в журнал предупреждение с цепочкой провайдеров (
from,to,attempts) для отладки. - Когда прерывание речи Twilio или завершение потока очищает очередь ожидающих запросов TTS, поставленные в очередь запросы воспроизведения завершаются, а не зависают, оставляя абонентов в ожидании окончания воспроизведения.
Примеры TTS
Только основной TTS
{messages: {tts: {provider: "openai",providers: { openai: { speakerVoice: "alloy" },},},},}Переопределение на ElevenLabs (только для звонков)
{plugins: {entries: {"voice-call": { config: { tts: { provider: "elevenlabs", providers: { elevenlabs: { apiKey: "elevenlabs_key", speakerVoiceId: "pMsXgVXv3BLzUgSXRplE", modelId: "eleven_multilingual_v2", }, }, }, },},},},}Переопределение модели OpenAI (глубокое слияние)
{plugins: {entries: {"voice-call": { config: { tts: { providers: { openai: { model: "gpt-4o-mini-tts", speakerVoice: "marin", }, }, }, },},},},}Входящие звонки
По умолчанию политика входящих звонков — disabled. Чтобы разрешить входящие звонки, задайте:
{inboundPolicy: "allowlist",allowFrom: ["+15550001234"],inboundGreeting: "Здравствуйте! Чем я могу помочь?",}Автоматические ответы используют систему агентов. Настройте их с помощью responseModel,
responseSystemPrompt и responseTimeoutMs.
Маршрутизация по номерам
Используйте numbers, когда один плагин Voice Call принимает звонки на несколько телефонных
номеров и каждый номер должен работать как отдельная линия. Например,
для одного номера можно использовать неформального личного помощника, а для другого — деловой
образ, другого агента ответов и другой голос TTS.
Маршруты выбираются по предоставленному провайдером набранному номеру To. Ключи должны
быть номерами в формате E.164. При поступлении звонка Voice Call однократно определяет подходящий
маршрут, сохраняет его в записи звонка и повторно использует эту
итоговую конфигурацию для приветствия, классического пути автоматического ответа, пути
консультации в реальном времени и воспроизведения TTS. Если подходящего маршрута нет, используется глобальная
конфигурация Voice Call. Исходящие звонки не используют numbers; при инициировании звонка
явно передавайте адресата исходящего звонка, сообщение и сеанс.
Переопределения маршрутов в настоящее время поддерживают:
inboundGreetingttsagentIdresponseModelresponseSystemPromptresponseTimeoutMs
Значение маршрута tts глубоко сливается с глобальной конфигурацией Voice Call tts, поэтому
обычно достаточно переопределить только голос провайдера:
{inboundGreeting: "Здравствуйте, вы позвонили на основную линию.",responseSystemPrompt: "Вы — голосовой помощник по умолчанию.",tts: { provider: "openai", providers: { openai: { speakerVoice: "coral" }, },},numbers: { "+15550001111": { inboundGreeting: "Silver Fox Cards, чем я могу помочь?", responseSystemPrompt: "Вы — лаконичный специалист по бейсбольным карточкам.", tts: { providers: { openai: { speakerVoice: "alloy" }, }, }, },},}Контракт речевого вывода
Для автоматических ответов Voice Call добавляет в системную подсказку строгий контракт речевого вывода,
требующий ответа JSON {"spoken":"..."}. Voice Call
защитным образом извлекает текст речи:
- Игнорирует полезные нагрузки, помеченные как содержимое рассуждения или ошибки.
- Анализирует непосредственно JSON, JSON в блоке кода или встроенные ключи
"spoken". - При невозможности анализа использует обычный текст и удаляет начальные абзацы, предположительно содержащие планирование или метаданные.
Благодаря этому воспроизводимая речь содержит только текст, предназначенный для вызывающего абонента, а текст планирования не попадает в аудио.
Поведение при начале разговора
Для исходящих звонков conversation обработка первого сообщения связана с текущим
состоянием воспроизведения:
- Очистка очереди при перебивании и автоматический ответ подавляются только пока начальное приветствие активно воспроизводится.
- Если начальное воспроизведение завершается ошибкой, звонок возвращается в состояние
listening, а начальное сообщение остаётся в очереди для повторной попытки. - Начальное воспроизведение для потоковой передачи Twilio запускается при подключении потока без дополнительной задержки.
- Перебивание прерывает активное воспроизведение и удаляет из очереди ещё не воспроизводимые записи TTS Twilio. Удалённые записи завершаются со статусом пропущенных, поэтому логика последующего ответа может продолжить работу, не ожидая аудио, которое уже не будет воспроизведено.
- Голосовые разговоры в реальном времени используют собственную начальную реплику потока реального времени. Voice Call не отправляет устаревшее обновление TwiML
OPENCLAW_DOCS_MARKER:calloutOpen:U2F5для этого начального сообщения, поэтому исходящие сеансы<Connect><Stream>остаются подключёнными.
Льготный период при отключении потока Twilio
Когда медиапоток Twilio отключается, Voice Call ожидает 2000 мс, прежде чем автоматически завершить звонок:
- Если поток повторно подключается в течение этого периода, автоматическое завершение отменяется.
- Если после окончания льготного периода поток не регистрируется повторно, звонок завершается, чтобы активные звонки не зависали.
Очистка устаревших звонков
Используйте staleCallReaperSeconds (по умолчанию 120), чтобы завершать звонки, на которые
не ответили и которые не перешли в состояние активного разговора, например звонки
в режиме уведомления, для которых провайдер так и не отправил завершающий Webhook. Установите значение 0,
чтобы отключить эту функцию.
Очистка выполняется каждые 30 секунд и завершает только звонки, у которых отсутствует
временная метка answeredAt и которые ещё не находятся в конечном состоянии или состоянии активного разговора
(speaking/listening), поэтому отвеченные разговоры никогда не завершаются
этим таймером; maxDurationSeconds (по умолчанию 300) — это отдельное ограничение,
завершающее отвеченные звонки, которые длятся слишком долго.
Для потоков в стиле уведомлений, где операторы могут медленно доставлять Webhook
о звонке или ответе, увеличьте staleCallReaperSeconds относительно значения по умолчанию, чтобы медленные, но нормальные
звонки не завершались преждевременно; 120–300 секунд — разумный диапазон для промышленной эксплуатации.
{plugins: {entries: { "voice-call": { config: { maxDurationSeconds: 300, staleCallReaperSeconds: 120, }, },},},}Безопасность Webhook
Если перед Gateway расположен прокси-сервер или туннель, плагин восстанавливает публичный URL для проверки подписи. Эти параметры определяют, каким переадресованным заголовкам следует доверять:
webhookSecurity.allowedHostsstring[]Разрешённые хосты из переадресованных заголовков.
webhookSecurity.trustForwardingHeadersbooleanДоверять переадресованным заголовкам без списка разрешённых значений.
webhookSecurity.trustedProxyIPsstring[]Доверять переадресованным заголовкам, только если удалённый IP-адрес запроса присутствует в списке.
Дополнительные меры защиты:
- Защита Webhook от повторного воспроизведения включена для Twilio, Telnyx и Plivo. Повторно отправленные допустимые запросы Webhook подтверждаются, но их побочные эффекты пропускаются.
- Реплики разговора Twilio содержат токен отдельной реплики в обратных вызовах
<Gather>, поэтому устаревшие или повторно воспроизведённые обратные вызовы речи не могут удовлетворить ожидание более новой расшифровки реплики. - Неаутентифицированные запросы Webhook отклоняются до чтения тела, если отсутствуют обязательные заголовки подписи провайдера.
- Webhook voice-call использует общий профиль чтения тела до аутентификации (максимальный размер тела 64 КБ, тайм-аут чтения 5 секунд), а также ограничение количества выполняющихся запросов для каждого ключа (по умолчанию 8 одновременных запросов на ключ) до проверки подписи.
Пример со стабильным публичным хостом:
{plugins: {entries: { "voice-call": { config: { publicUrl: "https://voice.example.com/voice/webhook", webhookSecurity: { allowedHosts: ["voice.example.com"], }, }, },},},}CLI
openclaw voicecall call --to "+15555550123" --message "Привет от OpenClaw"openclaw voicecall start --to "+15555550123" # псевдоним для callopenclaw voicecall continue --call-id <id> --message "Есть вопросы?"openclaw voicecall speak --call-id <id> --message "Одну минуту"openclaw voicecall dtmf --call-id <id> --digits "ww123456#"openclaw voicecall end --call-id <id>openclaw voicecall status --call-id <id>openclaw voicecall tailopenclaw voicecall latency # сводка задержек реплик из журналовopenclaw voicecall expose --mode funnelЕсли Gateway уже запущен, рабочие команды voicecall
делегируются среде выполнения voice-call, принадлежащей Gateway, чтобы CLI не привязывал
второй сервер Webhook. Если Gateway недоступен, команды переключаются на
автономную среду выполнения CLI.
latency считывает calls.jsonl из стандартного пути хранилища voice-call. Используйте
--file <path>, чтобы указать другой журнал, и --last <n>, чтобы ограничить
анализ последними N записями (по умолчанию 200). Вывод включает минимальное, максимальное и среднее значения,
p50 и p95 для задержки реплики и времени ожидания прослушивания.
Инструмент агента
Имя инструмента: 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 |
Плагин voice-call поставляется с соответствующим навыком агента.
RPC Gateway
| Метод | Аргументы | Примечания |
|---|---|---|
voicecall.initiate |
to?, message, mode?, sessionKey?, requesterSessionKey? |
Если to не указан, используется конфигурация toNumber. |
voicecall.start |
to, message?, mode?, dtmfSequence?, sessionKey? |
Аналогично initiate, но также принимает dtmfSequence до подключения. |
voicecall.continue |
callId, message |
Блокирует выполнение до завершения хода; возвращает расшифровку. |
voicecall.continue.start |
callId, message |
Асинхронный вариант: немедленно возвращает operationId. |
voicecall.continue.result |
operationId |
Опрашивает ожидающую операцию voicecall.continue.start для получения результата. |
voicecall.speak |
callId, message |
Воспроизводит речь без ожидания; использует мост реального времени, если realtime.enabled. |
voicecall.dtmf |
callId, digits |
|
voicecall.end |
callId |
|
voicecall.status |
callId? |
Не указывайте callId, чтобы вывести все активные вызовы. |
dtmfSequence допустим только с mode: "conversation"; вызовы в режиме уведомления,
которым после установления соединения требуется передача цифр, должны использовать
voicecall.dtmf после создания вызова.
Устранение неполадок
Во время настройки не удаётся открыть доступ к Webhook
Запустите настройку в той же среде, где работает Gateway:
openclaw voicecall setupopenclaw voicecall setup --jsonДля 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 и другие диапазоны
NAT операторского класса в качестве publicUrl.
Исходящие вызовы Twilio в режиме уведомления отправляют исходный TwiML OPENCLAW_DOCS_MARKER:calloutOpen:U2F5 непосредственно
в запросе на создание вызова, поэтому первое голосовое сообщение не зависит от
получения TwiML для Webhook службой Twilio. Публичный Webhook по-прежнему необходим для обратных
вызовов состояния, разговорных вызовов, DTMF до подключения, потоков реального времени и
управления вызовом после подключения.
Используйте один способ открытия публичного доступа:
{plugins: {entries: {"voice-call": { config: { publicUrl: "https://voice.example.com/voice/webhook", // или tunnel: { provider: "ngrok" }, // или tailscale: { mode: "funnel", path: "/voice/webhook" }, },},},},}После изменения конфигурации перезапустите или перезагрузите Gateway, затем выполните:
openclaw voicecall setupopenclaw voicecall smokevoicecall 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либоTELNYX_API_KEY,TELNYX_CONNECTION_IDиTELNYX_PUBLIC_KEY. - Plivo:
plivo.authId,plivo.authTokenиfromNumberлибоPLIVO_AUTH_IDиPLIVO_AUTH_TOKEN.
Учётные данные должны находиться на хосте Gateway. Изменение локального профиля оболочки не влияет на уже работающий Gateway, пока он не будет перезапущен или не перезагрузит своё окружение.
Вызовы начинаются, но Webhook от провайдера не поступают
Убедитесь, что в консоли провайдера указан точный URL публичного Webhook:
https://voice.example.com/voice/webhookЗатем проверьте состояние среды выполнения:
openclaw voicecall status --call-id <id>openclaw voicecall tailopenclaw logs --followРаспространённые причины:
publicUrlуказывает на путь, отличный отserve.path.- URL туннеля изменился после запуска Gateway.
- Прокси перенаправляет запрос, но удаляет или изменяет заголовки хоста или протокола.
- Брандмауэр или DNS направляет публичное имя хоста не на Gateway.
- Gateway был перезапущен без включённого плагина Voice Call.
Если перед Gateway расположен обратный прокси или туннель, задайте
в webhookSecurity.allowedHosts публичное имя хоста либо используйте
webhookSecurity.trustedProxyIPs для известного адреса прокси. Используйте
webhookSecurity.trustForwardingHeaders только тогда, когда граница прокси
находится под вашим контролем.
Ошибка проверки подписи
Подписи провайдера проверяются относительно публичного URL, который OpenClaw восстанавливает из входящего запроса. Если проверка подписи завершается ошибкой:
- Убедитесь, что URL Webhook провайдера в точности совпадает с
publicUrl, включая схему, хост и путь. - Для URL бесплатного тарифа ngrok обновляйте
publicUrlпри изменении имени хоста туннеля. - Убедитесь, что прокси сохраняет исходные заголовки хоста и протокола, либо настройте
webhookSecurity.allowedHosts. - Не включайте
skipSignatureVerificationза пределами локального тестирования.
Не удаётся подключиться к Google Meet через Twilio
Google Meet использует этот плагин для подключения через телефонный доступ Twilio. Сначала проверьте Voice Call:
openclaw voicecall setupopenclaw voicecall smoke --to "+15555550123"Затем отдельно проверьте транспорт Google Meet:
openclaw googlemeet setup --transport twilioЕсли Voice Call работает, но участник не подключается к встрече, проверьте
номер телефонного доступа Meet, PIN-код и --dtmf-sequence. Телефонный вызов может работать
нормально, даже если встреча отклоняет или игнорирует неверную последовательность DTMF.
Google Meet запускает телефонный сегмент Twilio через voicecall.start с
последовательностью DTMF до подключения. Последовательности, производные от PIN-кода, включают
voiceCall.dtmfDelayMs плагина Google Meet (по умолчанию 12000 ms) в качестве начальных
цифр ожидания Twilio, поскольку подсказки телефонного доступа Meet могут поступать с задержкой. Затем Voice Call
перенаправляет вызов обратно на обработку в реальном времени до запроса вступительного приветствия.
Используйте openclaw logs --follow для просмотра трассировки этапов в реальном времени. При успешном подключении
Twilio к Meet события регистрируются в следующем порядке:
- Google Meet передаёт подключение через Twilio плагину Voice Call.
- Voice Call сохраняет TwiML с DTMF до подключения.
- Исходный TwiML Twilio обрабатывается и передаётся до начала обработки в реальном времени.
- Voice Call передаёт TwiML реального времени для вызова Twilio.
- Google Meet запрашивает вступительную речь с
voicecall.speakпосле задержки, следующей за DTMF.
openclaw voicecall tail по-прежнему показывает сохранённые записи вызовов; это полезно для
просмотра состояния вызовов и расшифровок, но не все переходы Webhook и обработки в реальном времени
отображаются там.
В вызове реального времени отсутствует речь
Убедитесь, что включён только один режим аудио: realtime.enabled и
streaming.enabled не могут одновременно иметь значение true.
Для вызовов Twilio/Telnyx в реальном времени также проверьте следующее:
- Плагин провайдера реального времени загружен и зарегистрирован.
realtime.providerне задан или содержит имя зарегистрированного провайдера.- Ключ API провайдера доступен процессу Gateway.
openclaw logs --followпоказывает, что TwiML реального времени передан, мост реального времени запущен, а исходное приветствие поставлено в очередь.