音声通話(プラグイン)
OpenClaw の音声通話プラグインです。発信通知やマルチターンの着信通話会話に対応します。
対応プロバイダ:
twilio(Programmable Voice + Media Streams)telnyx(Call Control v2)plivo(Voice API + XML transfer + GetInput speech)mock(開発用/ネットワーク不要)
基本的な流れ:
- プラグインをインストール
- Gateway を再起動
plugins.entries.voice-call.configで設定openclaw voicecall ...またはvoice_callツールを使用
実行場所(ローカル vs リモート)
音声通話プラグインは Gateway プロセス内で動作します。
リモート Gateway を使用している場合は、Gateway を実行しているマシンにプラグインをインストール・設定し、Gateway を再起動してロードしてください。
インストール
方法 A: npm からインストール(推奨)
openclaw plugins install @openclaw/voice-call
インストール後、Gateway を再起動してください。
方法 B: ローカルフォルダからインストール(開発用、コピーなし)
openclaw plugins install ./extensions/voice-call
cd ./extensions/voice-call && pnpm install
インストール後、Gateway を再起動してください。
設定
plugins.entries.voice-call.config で設定します。
{
plugins: {
entries: {
"voice-call": {
enabled: true,
config: {
provider: "twilio", // または "telnyx" | "plivo" | "mock"
fromNumber: "+15550001234",
toNumber: "+15550005678",
twilio: {
accountSid: "ACxxxxxxxx",
authToken: "...",
},
telnyx: {
apiKey: "...",
connectionId: "...",
// Telnyx Mission Control Portal からの Webhook 公開鍵
// (Base64 文字列。TELNYX_PUBLIC_KEY でも設定可能)
publicKey: "...",
},
plivo: {
authId: "MAxxxxxxxxxxxxxxxxxxxx",
authToken: "...",
},
// Webhook サーバー
serve: {
port: 3334,
path: "/voice/webhook",
},
// Webhook セキュリティ(トンネル/プロキシ使用時に推奨)
webhookSecurity: {
allowedHosts: ["voice.example.com"],
trustedProxyIPs: ["100.64.0.1"],
},
// 公開エクスポーズ(いずれか 1 つ)
// publicUrl: "https://example.ngrok.app/voice/webhook",
// tunnel: { provider: "ngrok" },
// tailscale: { mode: "funnel", path: "/voice/webhook" }
outbound: {
defaultMode: "notify", // notify | conversation
},
streaming: {
enabled: true,
streamPath: "/voice/stream",
preStartTimeoutMs: 5000,
maxPendingConnections: 32,
maxPendingConnectionsPerIp: 4,
maxConnections: 128,
},
},
},
},
},
}
補足:
- Twilio/Telnyx には公開到達可能な Webhook URL が必要です。
- 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は有効なstartフレームを送信しないソケットをクローズします。streaming.maxPendingConnectionsは認証前のプレスタートソケットの合計を制限します。streaming.maxPendingConnectionsPerIpはソース IP ごとの認証前プレスタートソケットを制限します。streaming.maxConnectionsはオープンなメディアストリームソケットの合計(保留中 + アクティブ)を制限します。
古い通話のリーパー
staleCallReaperSeconds を使用して、終端の Webhook を受信しない通話(notify モードの通話が完了しない場合など)を終了します。デフォルトは 0(無効)です。
推奨範囲:
- 本番環境: notify フローの場合は
120〜300秒。 - この値は通常の通話が完了できるよう
maxDurationSecondsより大きく設定してください。目安はmaxDurationSeconds + 30〜60秒です。
例:
{
plugins: {
entries: {
"voice-call": {
config: {
maxDurationSeconds: 300,
staleCallReaperSeconds: 360,
},
},
},
},
}
Webhook セキュリティ
プロキシやトンネルが Gateway の前にある場合、プラグインは署名検証用に公開 URL を再構築します。以下のオプションで、信頼する転送ヘッダーを制御します。
webhookSecurity.allowedHosts は転送ヘッダーのホストを許可リストに追加します。
webhookSecurity.trustForwardingHeaders は許可リストなしで転送ヘッダーを信頼します。
webhookSecurity.trustedProxyIPs はリクエストのリモート IP がリストに一致する場合のみ転送ヘッダーを信頼します。
Twilio と Plivo では Webhook リプレイ保護が有効です。リプレイされた有効な Webhook リクエストは確認応答されますが、副作用はスキップされます。
Twilio の通話ターンには <Gather> コールバックにターンごとのトークンが含まれるため、古い/リプレイされた音声コールバックは新しい保留中のトランスクリプトターンに適合できません。
安定した公開ホストを使用する例:
{
plugins: {
entries: {
"voice-call": {
config: {
publicUrl: "https://voice.example.com/voice/webhook",
webhookSecurity: {
allowedHosts: ["voice.example.com"],
},
},
},
},
},
}
通話用 TTS
音声通話はコアの messages.tts 設定(OpenAI または ElevenLabs)を通話時のストリーミングスピーチに使用します。プラグイン設定で同じ形式でオーバーライドでき、messages.tts とディープマージされます。
{
tts: {
provider: "elevenlabs",
elevenlabs: {
voiceId: "pMsXgVXv3BLzUgSXRplE",
modelId: "eleven_multilingual_v2",
},
},
}
補足:
- Edge TTS は音声通話では無視されます(テレフォニー音声には PCM が必要で、Edge の出力は信頼性が低いです)。
- Twilio メディアストリーミングが有効な場合はコア TTS が使用されます。それ以外ではプロバイダネイティブの音声にフォールバックします。
その他の例
コア TTS のみ使用(オーバーライドなし):
{
messages: {
tts: {
provider: "openai",
openai: { voice: "alloy" },
},
},
}
通話のみ ElevenLabs にオーバーライド(他はコアデフォルトを維持):
{
plugins: {
entries: {
"voice-call": {
config: {
tts: {
provider: "elevenlabs",
elevenlabs: {
apiKey: "elevenlabs_key",
voiceId: "pMsXgVXv3BLzUgSXRplE",
modelId: "eleven_multilingual_v2",
},
},
},
},
},
},
}
通話のみ OpenAI モデルをオーバーライド(ディープマージの例):
{
plugins: {
entries: {
"voice-call": {
config: {
tts: {
openai: {
model: "gpt-4o-mini-tts",
voice: "marin",
},
},
},
},
},
},
}
着信通話
着信ポリシーのデフォルトは disabled です。着信通話を有効にするには:
{
inboundPolicy: "allowlist",
allowFrom: ["+15550001234"],
inboundGreeting: "Hello! How can I help?",
}
inboundPolicy: "allowlist" は低保証の発信者 ID スクリーニングです。プラグインはプロバイダから提供される From 値を正規化し、allowFrom と照合します。Webhook 検証はプロバイダの配信とペイロードの整合性を認証しますが、PSTN/VoIP の発信番号所有権を証明するものではありません。allowFrom は発信者 ID フィルタリングとして扱ってください。強力な発信者認証ではありません。
自動応答はエージェントシステムを使用します。以下で調整:
responseModelresponseSystemPromptresponseTimeoutMs
CLI
openclaw voicecall call --to "+15555550123" --message "Hello from OpenClaw"
openclaw voicecall continue --call-id <id> --message "Any questions?"
openclaw voicecall speak --call-id <id> --message "One moment"
openclaw voicecall end --call-id <id>
openclaw voicecall status --call-id <id>
openclaw voicecall tail
openclaw voicecall expose --mode funnel
エージェントツール
ツール名: voice_call
アクション:
initiate_call(message, to?, mode?)continue_call(callId, message)speak_to_user(callId, message)end_call(callId)get_status(callId)
このリポジトリには skills/voice-call/SKILL.md に対応するスキルドキュメントが含まれています。
Gateway RPC
voicecall.initiate(to?、message、mode?)voicecall.continue(callId、message)voicecall.speak(callId、message)voicecall.end(callId)voicecall.status(callId)