---
read_when:
    - Вы хотите совершить исходящий голосовой вызов из OpenClaw
    - Вы настраиваете или разрабатываете плагин голосовых вызовов
    - Вам нужна голосовая связь в реальном времени или потоковая транскрипция для телефонии
sidebarTitle: Voice call
summary: Совершайте исходящие и принимайте входящие голосовые вызовы через Twilio, Telnyx или Plivo с опциональной голосовой связью в реальном времени и потоковой транскрипцией
title: Плагин голосовых вызовов
x-i18n:
    generated_at: "2026-07-13T18:38:28Z"
    model: gpt-5.6
    postprocess_version: locale-links-v1
    prompt_version: 24
    provider: openai
    source_hash: d5cc3700f6d63f2bb1db2b3d0a5f9128c89719d06b48721c32db3d85353e423f
    source_path: plugins/voice-call.md
    workflow: 16
---

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

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

<Note>
Плагин голосовых вызовов работает **внутри процесса Gateway**. Если вы используете
удалённый Gateway, установите и настройте плагин на компьютере, где запущен
Gateway, а затем перезапустите Gateway, чтобы загрузить его.
</Note>

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

<Steps>
  <Step title="Установите плагин">
    <Tabs>
      <Tab title="Из npm">
        ```bash
        openclaw plugins install @openclaw/voice-call
        ```
      </Tab>
      <Tab title="Из локальной папки (для разработки)">
        ```bash
        PLUGIN_SRC=./path/to/local/voice-call-plugin
        openclaw plugins install "$PLUGIN_SRC"
        cd "$PLUGIN_SRC" && pnpm install
        ```
      </Tab>
    </Tabs>

    Используйте пакет без указания версии, чтобы следовать текущему тегу выпуска. Закрепляйте точную
    версию только тогда, когда требуется воспроизводимая установка. После этого перезапустите Gateway,
    чтобы плагин загрузился.

  </Step>
  <Step title="Настройте провайдера и Webhook">
    Задайте конфигурацию в `plugins.entries.voice-call.config` (см. раздел
    [Конфигурация](#configuration) ниже). Необходимый минимум: `provider`, учётные данные
    провайдера, `fromNumber` и общедоступный URL-адрес Webhook.
  </Step>
  <Step title="Проверьте настройку">
    ```bash
    openclaw voicecall setup
    openclaw voicecall setup --json
    ```

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

  </Step>
  <Step title="Выполните быструю проверку">
    ```bash
    openclaw voicecall smoke
    openclaw voicecall smoke --to "+15555550123"
    ```

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

    ```bash
    openclaw voicecall smoke --to "+15555550123" --yes
    ```

  </Step>
</Steps>

<Warning>
Для Twilio, Telnyx и Plivo настройка должна определять **общедоступный URL-адрес Webhook**.
Если `publicUrl`, URL-адрес туннеля, URL-адрес Tailscale или резервный адрес сервера
указывает на loopback-адрес или адрес в частной сети, настройка завершается с ошибкой вместо
запуска провайдера, который не сможет получать Webhook от оператора связи.
</Warning>

## Конфигурация

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

<Note>
Учётные данные голосовых вызовов поддерживают 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](/ru/reference/secretref-credential-surface).
</Note>

```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`. См. [Входящие вызовы](#inbound-calls). |
| `allowFrom`                     | `[]`         | Список разрешений E.164 для `inboundPolicy: "allowlist"`.                              |
| `maxDurationSeconds`            | `300`        | Жёсткое ограничение длительности каждого вызова, применяемое независимо от состояния ответа. |
| `staleCallReaperSeconds`        | `120`        | См. [Очистка устаревших вызовов](#stale-call-reaper). `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 в регионах за пределами США](https://www.twilio.com/docs/global-infrastructure/using-the-twilio-rest-api-in-a-non-us-region).

<AccordionGroup>
  <Accordion title="Примечания о доступности и безопасности провайдеров">
    - Для 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.

  </Accordion>
  <Accordion title="Ограничения потоковых подключений">
    - `streaming.preStartTimeoutMs` (по умолчанию `5000`) закрывает сокеты, которые так и не отправили допустимый кадр `start`.
    - `streaming.maxPendingConnections` (по умолчанию `32`) ограничивает общее количество неаутентифицированных сокетов до начала сеанса.
    - `streaming.maxPendingConnectionsPerIp` (по умолчанию `4`) ограничивает количество неаутентифицированных сокетов до начала сеанса для каждого IP-адреса источника.
    - `streaming.maxConnections` (по умолчанию `128`) ограничивает общее количество открытых сокетов медиапотоков (ожидающих и активных).

  </Accordion>
  <Accordion title="Миграции устаревшей конфигурации">
    При разборе конфигурации эти устаревшие ключи автоматически нормализуются, а в журнал
    записывается предупреждение с путём замены; совместимый переходный слой будет удалён в будущем
    выпуске (`2026.6.0`), поэтому запустите `openclaw doctor --fix`, чтобы преобразовать сохранённую
    конфигурацию в каноническую форму:

    - `provider: "log"` → `provider: "mock"`
    - `twilio.from` → `fromNumber`
    - `streaming.sttProvider` → `streaming.provider`
    - `streaming.openaiApiKey` → `streaming.providers.openai.apiKey`
    - `streaming.sttModel` → `streaming.providers.openai.model`
    - `streaming.silenceDurationMs` → `streaming.providers.openai.silenceDurationMs`
    - `streaming.vadThreshold` → `streaming.providers.openai.vadThreshold`
    - `realtime.agentContext.includeSystemPrompt` удалён (контекст реального времени теперь использует сгенерированную инструкцию агента)

  </Accordion>
</AccordionGroup>

## Область действия сеанса

По умолчанию плагин голосовых вызовов использует `sessionScope: "per-phone"`, поэтому повторные вызовы от
одного и того же звонящего сохраняют память диалога. Задайте `sessionScope: "per-call"`, если
каждый вызов через оператора должен начинаться с нового контекста, например для службы приёма,
бронирования, IVR или подключения к Google Meet, где один и тот же номер телефона может
соответствовать разным встречам.

Плагин голосовых вызовов сохраняет сгенерированные ключи сеансов в пространстве имён настроенного агента
(`agent:<agentId>:voice:*`). Явно заданные необработанные ключи интеграции разрешаются в
том же пространстве имён: канонический ключ `agent:<configuredAgentId>:*` сохраняет этого
владельца и учитывает псевдонимы основного `session.mainKey`/глобальной области; сторонний или
некорректный ввод `agent:*` помещается в область настроенного агента как непрозрачный ключ;
`global` и `unknown` остаются глобальными сигнальными значениями.

## Голосовые диалоги в реальном времени

`realtime` выбирает провайдера полнодуплексной голосовой связи в реальном времени для звука активного вызова.
Он не связан с `streaming`, который только перенаправляет звук провайдерам
транскрипции в реальном времени.

<Warning>
`realtime.enabled` нельзя использовать совместно с `streaming.enabled`. Выберите один
аудиорежим для каждого вызова.
</Warning>

Текущее поведение среды выполнения:

- `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"],
            },
          },
        },
      },
    },
  },
}
```

### Примеры провайдеров реального времени

<Tabs>
  <Tab title="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",
                  },
                },
              },
            },
          },
        },
      },
    }
    ```

  </Tab>
  <Tab title="OpenAI">
    ```json5
    {
      plugins: {
        entries: {
          "voice-call": {
            config: {
              realtime: {
                enabled: true,
                provider: "openai",
                providers: {
                  openai: { apiKey: "${OPENAI_API_KEY}" },
                },
              },
            },
          },
        },
      },
    }
    ```
  </Tab>
</Tabs>

См. разделы [Провайдер Google](/ru/providers/google) и
[Провайдер OpenAI](/ru/providers/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 записывает предупреждение в журнал и пропускает потоковую передачу мультимедиа вместо завершения всего плагина с ошибкой.

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

<Tabs>
  <Tab title="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,
                  },
                },
              },
            },
          },
        },
      },
    }
    ```

  </Tab>
  <Tab title="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",
                  },
                },
              },
            },
          },
        },
      },
    }
    ```

  </Tab>
</Tabs>

## TTS для вызовов

Voice Call использует основную конфигурацию `messages.tts` для потокового синтеза речи во время
вызовов. Её можно переопределить в конфигурации плагина, используя **ту же структуру** —
она глубоко объединяется с `messages.tts`.

```json5
{
  tts: {
    provider: "elevenlabs",
    providers: {
      elevenlabs: {
        speakerVoiceId: "pMsXgVXv3BLzUgSXRplE",
        modelId: "eleven_multilingual_v2",
      },
    },
  },
}
```

<Warning>
**Синтез речи Microsoft игнорируется для голосовых вызовов.** Для телефонного синтеза требуется
провайдер, реализующий вывод для телефонии; провайдер синтеза речи
Microsoft его не реализует, поэтому при вызовах он пропускается, а вместо него выполняются попытки
использовать другие провайдеры из цепочки резервных вариантов.
</Warning>

Примечания о поведении:

- Устаревшие ключи `tts.<provider>` в конфигурации плагина (`openai`, `elevenlabs`, `microsoft`, `edge`) исправляются командой `openclaw doctor --fix`; в сохраняемой конфигурации следует использовать `tts.providers.<provider>`.
- Основной TTS используется, когда включена потоковая передача мультимедиа Twilio; в противном случае для вызовов используются встроенные голоса провайдера.
- Если поток мультимедиа Twilio уже активен, Voice Call не переключается на резервный вариант TwiML `<Say>`. Если в этом состоянии телефонный TTS недоступен, запрос воспроизведения завершается с ошибкой вместо смешивания двух путей воспроизведения.
- Когда телефонный TTS переключается на резервного провайдера, Voice Call записывает в журнал предупреждение с цепочкой провайдеров (`from`, `to`, `attempts`) для отладки.
- Когда прерывание речи Twilio или завершение потока очищает очередь ожидающих запросов TTS, поставленные в очередь запросы воспроизведения завершаются, а не зависают, оставляя абонентов в ожидании окончания воспроизведения.

### Примеры TTS

<Tabs>
  <Tab title="Только основной TTS">
```json5
{
  messages: {
    tts: {
      provider: "openai",
      providers: {
        openai: { speakerVoice: "alloy" },
      },
    },
  },
}
```
  </Tab>
  <Tab title="Переопределение на ElevenLabs (только для звонков)">
```json5
{
  plugins: {
    entries: {
      "voice-call": {
        config: {
          tts: {
            provider: "elevenlabs",
            providers: {
              elevenlabs: {
                apiKey: "elevenlabs_key",
                speakerVoiceId: "pMsXgVXv3BLzUgSXRplE",
                modelId: "eleven_multilingual_v2",
              },
            },
          },
        },
      },
    },
  },
}
```
  </Tab>
  <Tab title="Переопределение модели OpenAI (глубокое слияние)">
```json5
{
  plugins: {
    entries: {
      "voice-call": {
        config: {
          tts: {
            providers: {
              openai: {
                model: "gpt-4o-mini-tts",
                speakerVoice: "marin",
              },
            },
          },
        },
      },
    },
  },
}
```
  </Tab>
</Tabs>

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

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

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

<Warning>
`inboundPolicy: "allowlist"` — это проверка идентификатора вызывающего абонента с низким уровнем достоверности. Плагин
нормализует предоставленное провайдером значение `From` и сравнивает его с `allowFrom`.
Проверка Webhook подтверждает доставку провайдером и целостность полезной нагрузки,
но **не** подтверждает принадлежность номера вызывающему абоненту PSTN/VoIP. Рассматривайте
`allowFrom` как фильтрацию идентификатора вызывающего абонента, а не как надёжное подтверждение его личности.
</Warning>

Автоматические ответы используют систему агентов. Настройте их с помощью `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 `<Say>` для этого начального сообщения, поэтому исходящие сеансы `<Connect><Stream>` остаются подключёнными.

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

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

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

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

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

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

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

```json5
{
  plugins: {
    entries: {
      "voice-call": {
        config: {
          maxDurationSeconds: 300,
          staleCallReaperSeconds: 120,
        },
      },
    },
  },
}
```

## Безопасность Webhook

Если перед Gateway расположен прокси-сервер или туннель, плагин восстанавливает
публичный URL для проверки подписи. Эти параметры определяют, каким
переадресованным заголовкам следует доверять:

<ParamField path="webhookSecurity.allowedHosts" type="string[]">
  Разрешённые хосты из переадресованных заголовков.
</ParamField>
<ParamField path="webhookSecurity.trustForwardingHeaders" type="boolean">
  Доверять переадресованным заголовкам без списка разрешённых значений.
</ParamField>
<ParamField path="webhookSecurity.trustedProxyIPs" type="string[]">
  Доверять переадресованным заголовкам, только если удалённый IP-адрес запроса присутствует в списке.
</ParamField>

Дополнительные меры защиты:

- Защита Webhook **от повторного воспроизведения** включена для Twilio, Telnyx и Plivo. Повторно отправленные допустимые запросы Webhook подтверждаются, но их побочные эффекты пропускаются.
- Реплики разговора Twilio содержат токен отдельной реплики в обратных вызовах `<Gather>`, поэтому устаревшие или повторно воспроизведённые обратные вызовы речи не могут удовлетворить ожидание более новой расшифровки реплики.
- Неаутентифицированные запросы 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"   # псевдоним для call
openclaw 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 tail
openclaw 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 setup
openclaw 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 `<Say>` непосредственно
в запросе на создание вызова, поэтому первое голосовое сообщение не зависит от
получения 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 setup
openclaw 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 tail
openclaw 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 setup
openclaw 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 реального времени передан, мост реального времени запущен, а исходное приветствие поставлено в очередь.

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

- [Режим разговора](/ru/nodes/talk)
- [Преобразование текста в речь](/ru/tools/tts)
- [Голосовая активация](/ru/nodes/voicewake)
