mock(開発用、ネットワークなし)、plivo(Voice API + XML 転送 +
GetInput 音声)、telnyx(Call Control v2)、twilio(Programmable Voice +
Media Streams)。
Voice Call Plugin は Gateway プロセス内 で実行されます。
リモート Gateway を使用する場合は、Gateway を実行しているマシンに Plugin を
インストールして設定し、Gateway を再起動して読み込んでください。
クイックスタート
1
Plugin をインストール
- npm から
- ローカルフォルダーから(開発用)
2
プロバイダーと Webhook を設定
plugins.entries.voice-call.config 配下に設定します(以下の
設定を参照)。最低限必要なのは、provider、プロバイダーの
認証情報、fromNumber、およびパブリックに到達可能な Webhook URL です。3
セットアップを検証
streaming または realtime)が一方だけ有効であることを確認します。4
スモークテスト
--yes を追加します。設定
enabled: true であるにもかかわらず、選択したプロバイダーの認証情報が不足している場合、
Gateway の起動時に不足しているキーを含むセットアップ未完了の警告がログに記録され、
ランタイムの起動はスキップされます。コマンド、RPC 呼び出し、エージェントツールを使用した場合も、
不足している設定が正確に返されます。
Voice Call の認証情報は SecretRefs に対応しています。
plugins.entries.voice-call.config.twilio.authToken、plugins.entries.voice-call.config.realtime.providers.*.apiKey、plugins.entries.voice-call.config.streaming.providers.*.apiKey、plugins.entries.voice-call.config.tts.providers.*.apiKey は標準の SecretRef サーフェスを通じて解決されます。SecretRef 認証情報サーフェスを参照してください。設定リファレンス
上記に示していないplugins.entries.voice-call.config 配下のトップレベルキー:
Twilio はデフォルトで US1 REST エンドポイントを使用します。サポートされている
米国外の Region で通話を処理するには、
twilio.region を ie1 または au1 に設定し、
その Region の認証情報を使用します。
Twilio の米国外 REST API ガイドを参照してください。
プロバイダーの公開とセキュリティに関する注記
プロバイダーの公開とセキュリティに関する注記
- Twilio、Telnyx、Plivo はすべて、パブリックに到達可能な Webhook URL を必要とします。
mockはローカル開発用プロバイダーです(ネットワーク呼び出しなし)。- Telnyx では、
skipSignatureVerificationが true でない限り、telnyx.publicKey(またはTELNYX_PUBLIC_KEY)が必要です。 skipSignatureVerificationはローカルテスト専用です。- ngrok の無料プランでは、
publicUrlを正確な ngrok URL に設定してください。署名検証は常に適用されます。 tunnel.allowNgrokFreeTierLoopbackBypass: trueは、tunnel.provider="ngrok"であり、かつserve.bindがループバック(ngrok ローカルエージェント)の場合に限り、署名が無効な Twilio Webhook を許可します。ローカル開発専用です。- ngrok の無料プランの URL は変更されたり、中間ページの動作が追加されたりする場合があります。
publicUrlがずれると、Twilio の署名検証が失敗します。本番環境では、安定したドメインまたは Tailscale funnel を推奨します。
ストリーミング接続の上限
ストリーミング接続の上限
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は削除されました(リアルタイムコンテキストでは、生成されたエージェントプロンプトが使用されるようになりました)
セッションスコープ
デフォルトでは、Voice Call はsessionScope: "per-phone" を使用するため、同じ発信者からの
再通話でも会話メモリが維持されます。各キャリア通話を新しいコンテキストで
開始する必要がある場合は、sessionScope: "per-call" を設定します。たとえば、同じ電話番号が
異なるミーティングを表す可能性がある受付、予約、IVR、Google Meet ブリッジフローなどです。
Voice Call は、設定されたエージェント名前空間
(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)で、それぞれのプロバイダー Plugin によって登録されます。 - プロバイダーが所有する未加工の設定は
realtime.providers.<providerId>の下に配置されます。 - Voice Call は、共有の
openclaw_agent_consultリアルタイムツールをデフォルトで公開します。発信者がより深い推論、最新情報、または通常の OpenClaw ツールを求めた場合、リアルタイムモデルはこのツールを呼び出せます。 realtime.consultPolicyは、リアルタイムモデルがopenclaw_agent_consultを呼び出すタイミングに関するガイダンスを任意で追加します。realtime.agentContext.enabledはデフォルトでオフです。有効にすると、Voice Call はセッション設定時に、制限されたエージェント ID と選択されたワークスペースファイルのカプセルをリアルタイムプロバイダーの指示に挿入します。realtime.fastContext.enabledはデフォルトでオフです。有効にすると、Voice Call はまず相談内容についてインデックス化されたメモリ/セッションコンテキストを検索し、realtime.fastContext.timeoutMsの範囲内でそのスニペットをリアルタイムモデルに返します。realtime.fastContext.fallbackToConsultが true の場合に限り、その後で完全な相談エージェントにフォールバックします。realtime.providerが未登録のプロバイダーを指している場合、またはリアルタイム音声プロバイダーがまったく登録されていない場合、Voice Call は警告をログに記録し、Plugin 全体を失敗させる代わりにリアルタイムメディアをスキップします。realtime.enabledが true の場合、inboundPolicyを"disabled"にしてはなりません。validateProviderConfigはこの組み合わせを拒否します。- 相談セッションキーは、利用可能な場合は保存済みの通話セッションを再利用し、その後、設定済みの
sessionScope(デフォルトではper-phone、分離された通話ではper-call)にフォールバックします。
ツールポリシー
realtime.toolPolicy は相談の実行を制御します。
realtime.consultPolicy はリアルタイムモデルの指示のみを制御します。
エージェント音声コンテキスト
通常のターンで完全なエージェント相談の往復コストをかけずに、音声ブリッジを 設定済みの OpenClaw エージェントらしく応答させる場合は、realtime.agentContext を有効にします。
コンテキストカプセルはリアルタイムセッションの作成時に一度だけ追加されるため、
ターンごとのレイテンシーは増加しません。openclaw_agent_consult の呼び出しでは、
引き続き完全な OpenClaw エージェントが実行されるため、ツール処理、最新情報、
メモリ検索、またはワークスペースの状態に使用してください。
リアルタイムプロバイダーの例
- Google Gemini Live
- OpenAI
デフォルト:API キーは
realtime.providers.google.apiKey、GEMINI_API_KEY、
または GOOGLE_API_KEY、モデルは gemini-3.1-flash-live-preview、
音声は Kore です。長時間の再接続可能な通話のため、
sessionResumption と contextWindowCompression はデフォルトでオンです。
電話音声でより素早いターン交替を調整するには、silenceDurationMs、
startSensitivity、および endSensitivity を使用します。ストリーミング文字起こし
streaming は Twilio Media Streams をリアルタイム文字起こしプロバイダーに接続します。
従来のストリーミング経路には provider: "twilio" が必要です。
Telnyx、Plivo、またはモックを使用する設定は拒否されます。Telnyx のライブ音声では、
代わりに個別に認証された realtime.enabled 経路を使用します。
現在のランタイム動作:
streaming.providerは任意です。未設定の場合、Voice Call は最初に登録されたリアルタイム文字起こしプロバイダーを使用します。- 同梱のリアルタイム文字起こしプロバイダーは、Deepgram(
deepgram)、ElevenLabs(elevenlabs)、Mistral(mistral)、OpenAI(openai)、および xAI(xai)で、それぞれのプロバイダー Plugin によって登録されます。 - プロバイダーが所有する未加工の設定は
streaming.providers.<providerId>の下に配置されます。 - Twilio が受理されたストリームの
startメッセージを送信すると、Voice Call は直ちにストリームを登録し、プロバイダーが接続している間は受信メディアを文字起こしプロバイダーのキューに入れ、リアルタイム文字起こしの準備が完了した後にのみ最初の挨拶を開始します。 streaming.providerが未登録のプロバイダーを指している場合、またはプロバイダーが登録されていない場合、Voice Call は警告をログに記録し、Plugin 全体を失敗させる代わりにメディアストリーミングをスキップします。
ストリーミングプロバイダーの例
- OpenAI
- xAI
デフォルト:API キーは
streaming.providers.openai.apiKey または
OPENAI_API_KEY、モデルは gpt-4o-transcribe、silenceDurationMs: 800、
vadThreshold: 0.5 です。通話用 TTS
Voice Call は、通話でのストリーミング音声にコアのtts 設定を使用します。
Plugin 設定の下で同じ構造を使用して上書きできます。
これは tts とディープマージされます。
- Plugin 設定内の従来の
tts.<provider>キー(openai、elevenlabs、microsoft、edge)はopenclaw doctor --fixによって修復されます。コミットする設定ではtts.providers.<provider>を使用してください。 - Twilio メディアストリーミングが有効な場合はコア TTS が使用されます。それ以外の場合、通話はプロバイダー固有の音声にフォールバックします。
- Twilio メディアストリームがすでにアクティブな場合、Voice Call は TwiML
<Say>にフォールバックしません。その状態で電話用 TTS が利用できない場合、2 つの再生経路を混在させる代わりに再生リクエストが失敗します。 - 電話用 TTS がセカンダリプロバイダーにフォールバックすると、Voice Call はデバッグ用にプロバイダーチェーン(
from、to、attempts)を含む警告をログに記録します。 - Twilio の割り込みまたはストリームの終了処理によって保留中の TTS キューが消去されると、キュー内の再生リクエストは、再生完了を待つ発信者をハングさせることなく完了状態になります。
TTS の例
- コア TTS のみ
- ElevenLabs に上書き(通話のみ)
- OpenAI モデルの上書き(ディープマージ)
着信通話
着信ポリシーのデフォルトはdisabled です。着信通話を有効にするには、次のように設定します。
responseModel、
responseSystemPrompt、responseTimeoutMs で調整できます。
番号ごとのルーティング
1 つの Voice Call Plugin が複数の電話番号への通話を受信し、各番号を異なる回線のように動作させる場合は、numbers を使用します。たとえば、
ある番号では気軽なパーソナルアシスタントを使用し、別の番号ではビジネス向けの
ペルソナ、異なる応答エージェント、異なる TTS 音声を使用できます。
ルートは、プロバイダーから提供されたダイヤル先の To 番号に基づいて選択されます。キーは
E.164 番号でなければなりません。通話を受信すると、Voice Call は一致する
ルートを一度だけ解決し、一致したルートを通話レコードに保存して、その
有効な設定を、挨拶、従来の自動応答パス、リアルタイム
相談パス、TTS 再生に再利用します。一致するルートがない場合は、グローバルな Voice Call
設定が使用されます。発信通話では numbers を使用しません。通話の開始時に、発信先、
メッセージ、セッションを明示的に渡してください。
現在、ルートの上書きでサポートされている項目は次のとおりです。
inboundGreetingttsagentIdresponseModelresponseSystemPromptresponseTimeoutMs
tts ルート値は、グローバルな Voice Call の tts 設定にディープマージされるため、
通常はプロバイダーの音声だけを上書きできます。
音声出力の契約
自動応答では、Voice Call はシステムプロンプトに厳格な音声出力契約を追加し、{"spoken":"..."} JSON 応答を必須とします。Voice Call は
防御的に音声テキストを抽出します。
- 推論またはエラーコンテンツとしてマークされたペイロードを無視します。
- 直接の JSON、フェンス付き JSON、またはインラインの
"spoken"キーを解析します。 - プレーンテキストにフォールバックし、計画やメタ情報と思われる冒頭の段落を削除します。
会話開始時の動作
発信conversation 通話では、最初のメッセージの処理はライブ
再生状態に連動します。
- 割り込み時のキュー消去と自動応答は、最初の挨拶が実際に再生されている間のみ抑制されます。
- 最初の再生に失敗した場合、通話は
listeningに戻り、最初のメッセージは再試行のためキューに残ります。 - Twilio ストリーミングの最初の再生は、追加の遅延なしでストリーム接続時に開始されます。
- 割り込みは進行中の再生を中止し、キューに入っているもののまだ再生されていない Twilio TTS エントリを消去します。消去されたエントリはスキップ済みとして解決されるため、後続の応答ロジックは、再生されることのない音声を待たずに続行できます。
- リアルタイム音声会話では、リアルタイムストリーム自体の最初のターンを使用します。Voice Call は、その最初のメッセージに対して従来の
<Say>TwiML 更新を送信しないため、発信<Connect><Stream>セッションの接続が維持されます。
Twilio ストリーム切断の猶予期間
Twilio メディアストリームが切断されると、Voice Call は通話を 自動終了する前に 2000 ms 待機します。- その期間内にストリームが再接続された場合、自動終了はキャンセルされます。
- 猶予期間後にストリームが再登録されなかった場合、アクティブな通話が停止状態のまま残るのを防ぐため、通話を終了します。
古い通話のリーパー
応答されず、ライブ会話状態にも到達しない通話を終了するには、staleCallReaperSeconds(デフォルトは 120)を使用します。たとえば、プロバイダーが終了を示す Webhook を配信しない
通知モードの通話が該当します。無効にするには 0 に設定します。
リーパーは 30 秒ごとに実行され、answeredAt タイムスタンプがなく、
終了状態またはライブ状態(speaking/listening)にない通話だけを終了します。そのため、応答済みの会話が
このタイマーによって終了されることはありません。maxDurationSeconds(デフォルトは 300)は、
長時間続く応答済み通話を終了するための別の上限です。
通信事業者による呼び出し中または応答の Webhook 配信が遅れる可能性がある通知形式のフローでは、
遅いものの正常な通話が早期に終了されないように、staleCallReaperSeconds をデフォルトより大きくしてください。本番環境では
120~300 秒が妥当な範囲です。
Webhook のセキュリティ
Gateway の前段にプロキシまたはトンネルがある場合、Plugin は署名検証用の 公開 URL を再構築します。次のオプションで、信頼する転送ヘッダーを 制御します。string[]
転送ヘッダーからのホストを許可リストに登録します。
boolean
許可リストなしで転送ヘッダーを信頼します。
string[]
リクエストのリモート IP がリストに一致する場合のみ、転送ヘッダーを信頼します。
- Twilio、Telnyx、Plivo では、Webhook のリプレイ保護が有効です。再送された有効な Webhook リクエストは確認応答されますが、副作用の処理はスキップされます。
- Twilio の会話ターンでは、
<Gather>コールバックにターンごとのトークンが含まれるため、古いまたは再送された音声コールバックが、新しい保留中の文字起こしターンを完了させることはありません。 - プロバイダーが要求する署名ヘッダーがない場合、未認証の Webhook リクエストは本文の読み取り前に拒否されます。
- voice-call Webhook は、共有の認証前本文読み取りプロファイル(本文の最大サイズは 64 KB、読み取りタイムアウトは 5 秒)に加え、署名検証前にキーごとの処理中リクエスト上限(デフォルトではキーごとに 8 件の同時リクエスト)を使用します。
CLI
voicecall コマンドは
Gateway が所有する voice-call ランタイムに処理を委譲するため、CLI が
2 つ目の Webhook サーバーをバインドすることはありません。到達可能な Gateway がない場合、
コマンドはスタンドアロンの CLI ランタイムにフォールバックします。
latency は、デフォルトの voice-call ストレージパスから calls.jsonl を読み取ります。
別のログを指定するには --file <path> を使用し、分析対象を直近の N 件のレコード(デフォルトは 200)に制限するには
--last <n> を使用します。出力には、ターンのレイテンシとリッスン待機時間について、
最小値、最大値、平均値、p50、p95 が含まれます。
エージェントツール
ツール名:voice_call。
voice-call Plugin には、対応するエージェント Skills が同梱されています。
Gateway RPC
dtmfSequence は mode: "conversation" との組み合わせでのみ有効です。通知モードの通話で接続後に
数字を送信する必要がある場合は、通話が存在するようになってから
voicecall.dtmf を使用してください。
トラブルシューティング
セットアップで Webhook の公開に失敗する
Gateway を実行している環境と同じ環境からセットアップを実行します。twilio、telnyx、plivo では、webhook-exposure が正常である必要があります。
設定済みの publicUrl であっても、ローカルまたはプライベートな
ネットワーク空間を指している場合、通信事業者がそれらのアドレスへコールバックできないため失敗します。
localhost、127.0.0.1、0.0.0.0、10.x、172.16.x-172.31.x、
192.168.x、169.254.x、fc00::/7、fd00::/8、またはその他の通信事業者グレード NAT
範囲を publicUrl として使用しないでください。
Twilio の通知モードの発信通話では、最初の <Say> TwiML を通話作成リクエスト内で直接送信するため、
最初の音声メッセージは Twilio による Webhook TwiML の取得に依存しません。
ステータスコールバック、会話通話、接続前 DTMF、リアルタイムストリーム、
および接続後の通話制御には、引き続き公開 Webhook が必要です。
次のいずれかの公開方法を使用します。
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。
通話は開始するが、プロバイダーの Webhook が届かない
プロバイダーのコンソールが正確な公開 Webhook URL を指していることを確認します。publicUrlがserve.pathとは異なるパスを指している。- Gateway の起動後にトンネル URL が変更された。
- プロキシがリクエストを転送する際に、host/proto ヘッダーを削除または書き換えている。
- ファイアウォールまたは DNS により、公開ホスト名が Gateway 以外の場所へルーティングされている。
- Voice Call Plugin を有効にせずに Gateway が再起動された。
webhookSecurity.allowedHosts を公開ホスト名に設定するか、既知のプロキシアドレスには
webhookSecurity.trustedProxyIPs を使用します。webhookSecurity.trustForwardingHeaders は、
プロキシ境界を自身で管理している場合にのみ使用してください。
署名検証に失敗する
プロバイダーの署名は、OpenClaw が受信リクエストから再構築した公開 URL に対して 検証されます。署名に失敗する場合は、次を確認してください。- プロバイダーの Webhook URL が、スキーム、ホスト、パスを含めて
publicUrlと完全に一致することを確認する。 - ngrok の無料プランの URL では、トンネルのホスト名が変わったときに
publicUrlを更新する。 - プロキシが元の host および proto ヘッダーを維持していることを確認するか、
webhookSecurity.allowedHostsを設定する。 - ローカルテスト以外では
skipSignatureVerificationを有効にしない。
Google Meet の Twilio 参加に失敗する
Google Meet は、Twilio のダイヤルイン参加にこの Plugin を使用します。まず Voice Call を検証します。--dtmf-sequence を確認します。電話通話が正常でも、
誤った DTMF シーケンスを会議が拒否または無視する場合があります。
Google Meet は、接続前 DTMF シーケンスを指定して voicecall.start を介し、
Twilio の電話区間を開始します。PIN から生成されたシーケンスには、Google Meet
Plugin の voiceCall.dtmfDelayMs(デフォルト 12000 ms)が先頭の Twilio
待機数字として含まれます。これは、Meet のダイヤルインプロンプトが遅れて到着する場合があるためです。その後 Voice Call は、
イントロの挨拶が要求される前にリアルタイム処理へリダイレクトします。
ライブフェーズのトレースには openclaw logs --follow を使用します。正常な Twilio Meet
参加では、次の順序でログが記録されます。
- Google Meet が Twilio 参加を Voice Call に委任する。
- Voice Call が接続前 DTMF TwiML を保存する。
- Twilio の初期 TwiML が消費され、リアルタイム処理より前に提供される。
- Voice Call が Twilio 通話用のリアルタイム TwiML を提供する。
- Google Meet が DTMF 後の遅延後に
voicecall.speakを使用してイントロ音声を要求する。
openclaw voicecall tail には永続化された通話レコードが引き続き表示されます。これは
通話状態とトランスクリプトには役立ちますが、すべての Webhook/リアルタイム遷移が
表示されるわけではありません。
リアルタイム通話で音声が再生されない
有効な音声モードが 1 つだけであることを確認します。realtime.enabled と
streaming.enabled を同時に true にすることはできません。
リアルタイムの Twilio/Telnyx 通話では、次も確認してください。
- リアルタイムプロバイダーの Plugin が読み込まれ、登録されている。
realtime.providerが未設定であるか、登録済みプロバイダーを指定している。- プロバイダーの API キーを Gateway プロセスから利用できる。
openclaw logs --followに、リアルタイム TwiML の提供、リアルタイムブリッジの開始、最初の挨拶のキューへの追加が表示されている。