音声通話(プラグイン)

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 フローの場合は 120300 秒。
  • この値は通常の通話が完了できるよう 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 フィルタリングとして扱ってください。強力な発信者認証ではありません。

自動応答はエージェントシステムを使用します。以下で調整:

  • responseModel
  • responseSystemPrompt
  • responseTimeoutMs

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.initiateto?messagemode?
  • voicecall.continuecallIdmessage
  • voicecall.speakcallIdmessage
  • voicecall.endcallId
  • voicecall.statuscallId