Plugin guides

Плагин голосовых вызовов

Голосовые вызовы для OpenClaw через плагин: исходящие уведомления, многоходовые диалоги, полнодуплексная голосовая связь в реальном времени, потоковая транскрипция и входящие вызовы с политиками списков разрешений.

Провайдеры: mock (для разработки, без сети), plivo (Voice API + передача XML + распознавание речи GetInput), telnyx (Call Control v2), twilio (Programmable Voice + Media Streams).

Быстрый старт

  • Установите плагин

    Из npm

    bash
    openclaw plugins install @openclaw/voice-call

    Из локальной папки (для разработки)

    bash
    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.

  • Проверьте настройку

    bash
    openclaw voicecall setupopenclaw voicecall setup --json

    Проверяет, включён ли плагин, учётные данные провайдера, доступность Webhook и активен ли только один аудиорежим (streaming или realtime).

  • Выполните быструю проверку

    bash
    openclaw voicecall smokeopenclaw voicecall smoke --to "+15555550123"

    По умолчанию обе команды выполняются в тестовом режиме без реального вызова. Добавьте --yes, чтобы совершить короткий исходящий вызов с уведомлением:

    bash
    openclaw voicecall smoke --to "+15555550123" --yes
  • Конфигурация

    Если enabled: true, но у выбранного провайдера отсутствуют учётные данные, при запуске Gateway в журнал записывается предупреждение о незавершённой настройке с перечислением отсутствующих ключей, а среда выполнения не запускается. При использовании команд, вызовов RPC и инструментов агента они по-прежнему возвращают точный список отсутствующих параметров конфигурации.

    json5
    {  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.fromfromNumber
    • streaming.sttProviderstreaming.provider
    • streaming.openaiApiKeystreaming.providers.openai.apiKey
    • streaming.sttModelstreaming.providers.openai.model
    • streaming.silenceDurationMsstreaming.providers.openai.silenceDurationMs
    • streaming.vadThresholdstreaming.providers.openai.vadThreshold
    • realtime.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 и должны использоваться для работы с инструментами, получения актуальной информации, поиска в памяти или состояния рабочего пространства.

    json5
    {  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, чтобы настроить более быструю смену реплик для телефонного аудио.

    json5
    {  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

    json5
    {  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 принятого сообщения потока start Voice Call немедленно регистрирует поток, ставит входящие мультимедийные данные в очередь для обработки провайдером транскрипции, пока тот подключается, и запускает начальное приветствие только после готовности транскрипции в реальном времени.
    • Если streaming.provider указывает на незарегистрированного провайдера или ни один провайдер не зарегистрирован, Voice Call записывает предупреждение в журнал и пропускает потоковую передачу мультимедиа вместо завершения всего плагина с ошибкой.

    Примеры потоковых провайдеров

    OpenAI

    Значения по умолчанию: ключ API streaming.providers.openai.apiKey или OPENAI_API_KEY; модель gpt-4o-transcribe; silenceDurationMs: 800; vadThreshold: 0.5.

    json5
    {  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.

    json5
    {  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.

    json5
    {  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

    json5
    {messages: {tts: {provider: "openai",providers: {  openai: { speakerVoice: "alloy" },},},},}

    Переопределение на ElevenLabs (только для звонков)

    json5
    {plugins: {entries: {"voice-call": {  config: {    tts: {      provider: "elevenlabs",      providers: {        elevenlabs: {          apiKey: "elevenlabs_key",          speakerVoiceId: "pMsXgVXv3BLzUgSXRplE",          modelId: "eleven_multilingual_v2",        },      },    },  },},},},}

    Переопределение модели OpenAI (глубокое слияние)

    json5
    {plugins: {entries: {"voice-call": {  config: {    tts: {      providers: {        openai: {          model: "gpt-4o-mini-tts",          speakerVoice: "marin",        },      },    },  },},},},}

    Входящие звонки

    По умолчанию политика входящих звонков — disabled. Чтобы разрешить входящие звонки, задайте:

    json5
    {inboundPolicy: "allowlist",allowFrom: ["+15550001234"],inboundGreeting: "Здравствуйте! Чем я могу помочь?",}

    Автоматические ответы используют систему агентов. Настройте их с помощью responseModel, responseSystemPrompt и responseTimeoutMs.

    Маршрутизация по номерам

    Используйте numbers, когда один плагин Voice Call принимает звонки на несколько телефонных номеров и каждый номер должен работать как отдельная линия. Например, для одного номера можно использовать неформального личного помощника, а для другого — деловой образ, другого агента ответов и другой голос TTS.

    Маршруты выбираются по предоставленному провайдером набранному номеру To. Ключи должны быть номерами в формате E.164. При поступлении звонка Voice Call однократно определяет подходящий маршрут, сохраняет его в записи звонка и повторно использует эту итоговую конфигурацию для приветствия, классического пути автоматического ответа, пути консультации в реальном времени и воспроизведения TTS. Если подходящего маршрута нет, используется глобальная конфигурация Voice Call. Исходящие звонки не используют numbers; при инициировании звонка явно передавайте адресата исходящего звонка, сообщение и сеанс.

    Переопределения маршрутов в настоящее время поддерживают:

    • inboundGreeting
    • tts
    • agentId
    • responseModel
    • responseSystemPrompt
    • responseTimeoutMs

    Значение маршрута tts глубоко сливается с глобальной конфигурацией Voice Call tts, поэтому обычно достаточно переопределить только голос провайдера:

    json5
    {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 для этого начального сообщения, поэтому исходящие сеансы &lt;Connect&gt;&lt;Stream&gt; остаются подключёнными.

    Льготный период при отключении потока Twilio

    Когда медиапоток Twilio отключается, Voice Call ожидает 2000 мс, прежде чем автоматически завершить звонок:

    • Если поток повторно подключается в течение этого периода, автоматическое завершение отменяется.
    • Если после окончания льготного периода поток не регистрируется повторно, звонок завершается, чтобы активные звонки не зависали.

    Очистка устаревших звонков

    Используйте staleCallReaperSeconds (по умолчанию 120), чтобы завершать звонки, на которые не ответили и которые не перешли в состояние активного разговора, например звонки в режиме уведомления, для которых провайдер так и не отправил завершающий Webhook. Установите значение 0, чтобы отключить эту функцию.

    Очистка выполняется каждые 30 секунд и завершает только звонки, у которых отсутствует временная метка answeredAt и которые ещё не находятся в конечном состоянии или состоянии активного разговора (speaking/listening), поэтому отвеченные разговоры никогда не завершаются этим таймером; maxDurationSeconds (по умолчанию 300) — это отдельное ограничение, завершающее отвеченные звонки, которые длятся слишком долго.

    Для потоков в стиле уведомлений, где операторы могут медленно доставлять Webhook о звонке или ответе, увеличьте staleCallReaperSeconds относительно значения по умолчанию, чтобы медленные, но нормальные звонки не завершались преждевременно; 120300 секунд — разумный диапазон для промышленной эксплуатации.

    json5
    {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 содержат токен отдельной реплики в обратных вызовах &lt;Gather&gt;, поэтому устаревшие или повторно воспроизведённые обратные вызовы речи не могут удовлетворить ожидание более новой расшифровки реплики.
    • Неаутентифицированные запросы Webhook отклоняются до чтения тела, если отсутствуют обязательные заголовки подписи провайдера.
    • Webhook voice-call использует общий профиль чтения тела до аутентификации (максимальный размер тела 64 КБ, тайм-аут чтения 5 секунд), а также ограничение количества выполняющихся запросов для каждого ключа (по умолчанию 8 одновременных запросов на ключ) до проверки подписи.

    Пример со стабильным публичным хостом:

    json5
    {plugins: {entries: {  "voice-call": {    config: {      publicUrl: "https://voice.example.com/voice/webhook",      webhookSecurity: {        allowedHosts: ["voice.example.com"],      },    },  },},},}

    CLI

    bash
    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:

    bash
    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 до подключения, потоков реального времени и управления вызовом после подключения.

    Используйте один способ открытия публичного доступа:

    json5
    {plugins: {entries: {"voice-call": {  config: {    publicUrl: "https://voice.example.com/voice/webhook",    // или    tunnel: { provider: "ngrok" },    // или    tailscale: { mode: "funnel", path: "/voice/webhook" },  },},},},}

    После изменения конфигурации перезапустите или перезагрузите Gateway, затем выполните:

    bash
    openclaw voicecall setupopenclaw voicecall smoke

    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 либо 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:

    text
    https://voice.example.com/voice/webhook

    Затем проверьте состояние среды выполнения:

    bash
    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:

    bash
    openclaw voicecall setupopenclaw voicecall smoke --to "+15555550123"

    Затем отдельно проверьте транспорт Google Meet:

    bash
    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 реального времени передан, мост реального времени запущен, а исходное приветствие поставлено в очередь.

    Связанные разделы

    Was this useful?
    On this page

    On this page