Voice calls for OpenClaw via a Plugin. 支援出站通知、 多輪對話、全雙工即時語音、串流 轉錄,以及具允許清單政策的入站通話。 目前提供者:Documentation Index
Fetch the complete documentation index at: https://docs.openclaw.ai/llms.txt
Use this file to discover all available pages before exploring further.
twilio (Programmable Voice + Media Streams),
telnyx (Call Control v2), plivo (Voice API + XML transfer + GetInput
speech), mock (開發/無網路)。
Voice Call Plugin 會在 Gateway 程序內部 執行。如果你使用
遠端 Gateway,請在執行 Gateway 的機器上安裝並設定 Plugin,
然後重新啟動 Gateway 以載入它。
快速開始
安裝 Plugin
- 從 npm
- 從本機資料夾(開發)
設定提供者和 Webhook
在
plugins.entries.voice-call.config 下設定 config(完整形狀請參閱下方
設定)。至少需要:
provider、提供者憑證、fromNumber,以及可公開
存取的 Webhook URL。驗證設定
streaming 或 realtime)處於啟用狀態。腳本請使用
--json。設定
如果enabled: true 但所選提供者缺少憑證,
Gateway 啟動時會記錄 setup-incomplete 警告,列出缺少的 keys,並
略過啟動 runtime。Commands、RPC 呼叫和代理工具在使用時仍會
回傳確切缺少的提供者設定。
Voice-call 憑證接受 SecretRefs。
plugins.entries.voice-call.config.twilio.authToken 和 plugins.entries.voice-call.config.tts.providers.*.apiKey 會透過標準 SecretRef 表面解析;請參閱 SecretRef 憑證表面。提供者曝露與安全性注意事項
提供者曝露與安全性注意事項
- Twilio、Telnyx 和 Plivo 都需要 可公開存取 的 Webhook URL。
mock是本機開發提供者(不進行網路呼叫)。- Telnyx 需要
telnyx.publicKey(或TELNYX_PUBLIC_KEY),除非skipSignatureVerification為 true。 skipSignatureVerification僅供本機測試使用。- 在 ngrok 免費方案中,將
publicUrl設為確切的 ngrok URL;簽章驗證一律強制執行。 tunnel.allowNgrokFreeTierLoopbackBypass: true只會在tunnel.provider="ngrok"且serve.bind為 loopback(ngrok 本機代理)時,允許簽章無效的 Twilio Webhook。僅供本機開發使用。- Ngrok 免費方案 URL 可能會變更或加入中介頁行為;如果
publicUrl偏移,Twilio 簽章會失敗。正式環境:建議使用穩定網域或 Tailscale funnel。
串流連線上限
串流連線上限
streaming.preStartTimeoutMs會關閉從未傳送有效startframe 的 socket。streaming.maxPendingConnections會限制未驗證 pre-start socket 的總數。streaming.maxPendingConnectionsPerIp會限制每個來源 IP 的未驗證 pre-start socket 數量。streaming.maxConnections會限制開啟中的媒體串流 socket 總數(pending + active)。
舊版 config 遷移
舊版 config 遷移
使用
provider: "log"、twilio.from 或舊版
streaming.* OpenAI keys 的較舊 config,會由 openclaw doctor --fix 改寫。
Runtime 後備方案目前仍接受舊的 voice-call keys,但
改寫路徑是 openclaw doctor --fix,且 compat shim 是
暫時性的。自動遷移的 streaming keys:streaming.sttProvider→streaming.providerstreaming.openaiApiKey→streaming.providers.openai.apiKeystreaming.sttModel→streaming.providers.openai.modelstreaming.silenceDurationMs→streaming.providers.openai.silenceDurationMsstreaming.vadThreshold→streaming.providers.openai.vadThreshold
即時語音對話
realtime 會為即時通話
音訊選取全雙工即時語音提供者。它與 streaming 分開,後者只會將音訊轉送到
即時轉錄提供者。
目前 runtime 行為:
- Twilio Media Streams 支援
realtime.enabled。 realtime.provider是選用項。如果未設定,Voice Call 會使用第一個已註冊的即時語音提供者。- 內建即時語音提供者:Google Gemini Live (
google) 和 OpenAI (openai),由其提供者 Plugin 註冊。 - 提供者擁有的原始 config 位於
realtime.providers.<providerId>下。 - Voice Call 預設公開共用的
openclaw_agent_consult即時工具。當來電者要求更深入的推理、目前資訊,或一般 OpenClaw 工具時,即時模型可以呼叫它。 - 如果
realtime.provider指向未註冊的提供者,或完全沒有註冊任何即時語音提供者,Voice Call 會記錄警告並略過即時媒體,而不是讓整個 Plugin 失敗。 - Consult 工作階段 keys 會在可用時重用現有語音工作階段,然後退回使用來電者/被叫者電話號碼,讓後續 consult 呼叫在通話期間保留上下文。
工具政策
realtime.toolPolicy 控制 consult 執行:
| 政策 | 行為 |
|---|---|
safe-read-only | 公開 consult 工具,並將一般代理限制為 read、web_search、web_fetch、x_search、memory_search 和 memory_get。 |
owner | 公開 consult 工具,並讓一般代理使用正常的代理工具政策。 |
none | 不公開 consult 工具。自訂 realtime.tools 仍會傳遞給即時提供者。 |
即時提供者範例
- Google Gemini Live
- OpenAI
預設值:API key 來自
realtime.providers.google.apiKey、
GEMINI_API_KEY 或 GOOGLE_GENERATIVE_AI_API_KEY;模型
gemini-2.5-flash-native-audio-preview-12-2025;voice Kore。串流轉錄
streaming 會為即時通話音訊選取即時轉錄提供者。
目前 runtime 行為:
streaming.provider是選用項。如果未設定,Voice Call 會使用第一個已註冊的即時轉錄提供者。- 內建即時轉錄提供者:Deepgram (
deepgram)、ElevenLabs (elevenlabs)、Mistral (mistral)、OpenAI (openai) 和 xAI (xai),由其提供者 Plugin 註冊。 - 提供者擁有的原始 config 位於
streaming.providers.<providerId>下。 - 如果
streaming.provider指向未註冊的提供者,或沒有任何已註冊的提供者,Voice Call 會記錄警告並略過媒體串流,而不是讓整個 Plugin 失敗。
串流提供者範例
- OpenAI
- xAI
預設值:API key
streaming.providers.openai.apiKey 或
OPENAI_API_KEY;模型 gpt-4o-transcribe;silenceDurationMs: 800;
vadThreshold: 0.5.通話的 TTS
語音通話會使用核心messages.tts 設定,在通話中串流語音。你可以在 Plugin 設定下以相同結構覆寫它,這會與 messages.tts 進行深度合併。
- Plugin 設定內的舊版
tts.<provider>鍵(openai、elevenlabs、microsoft、edge)會由openclaw doctor --fix修復;提交的設定應使用tts.providers.<provider>。 - 啟用 Twilio 媒體串流時會使用核心 TTS;否則通話會退回使用提供者原生語音。
- 如果 Twilio 媒體串流已啟用,語音通話不會退回使用 TwiML
<Say>。如果在該狀態下電話 TTS 無法使用,播放請求會失敗,而不是混合兩條播放路徑。 - 當電話 TTS 退回到次要提供者時,語音通話會記錄包含提供者鏈(
from、to、attempts)的警告,方便除錯。 - 當 Twilio 插話或串流拆除清除待處理的 TTS 佇列時,已排入佇列的播放請求會完成結算,而不是讓來電者等待播放完成而卡住。
TTS 範例
- Core TTS only
- Override to ElevenLabs (calls only)
- OpenAI model override (deep-merge)
來電
來電策略預設為disabled。若要啟用來電,請設定:
responseModel、responseSystemPrompt 和 responseTimeoutMs 調整。
語音輸出合約
對於自動回覆,語音通話會將嚴格的語音輸出合約附加到系統提示:- 忽略標記為推理/錯誤內容的承載資料。
- 解析直接 JSON、圍欄 JSON,或行內
"spoken"鍵。 - 退回使用純文字,並移除可能是規劃/中繼說明的開頭段落。
對話啟動行為
對於外撥conversation 通話,第一則訊息處理會繫結至即時播放狀態:
- 只有在初始問候語正在主動播放時,才會抑制插話佇列清除與自動回覆。
- 如果初始播放失敗,通話會回到
listening,且初始訊息會維持佇列狀態以便重試。 - Twilio 串流的初始播放會在串流連線時開始,沒有額外延遲。
- 插話會中止作用中的播放,並清除已排入佇列但尚未播放的 Twilio TTS 項目。已清除的項目會解析為已略過,因此後續回覆邏輯可以繼續,不必等待永遠不會播放的音訊。
- 即時語音對話會使用即時串流自身的開場輪次。語音通話不會針對該初始訊息送出舊版
<Say>TwiML 更新,因此外撥<Connect><Stream>工作階段會保持附加狀態。
Twilio 串流中斷寬限
當 Twilio 媒體串流中斷連線時,語音通話會等待 2000 毫秒 後才自動結束通話:- 如果串流在該時間窗內重新連線,會取消自動結束。
- 如果寬限期後沒有串流重新註冊,通話會被結束,以避免作用中的通話卡住。
過期通話清除器
使用staleCallReaperSeconds 結束從未收到終止 Webhook 的通話(例如永不完成的通知模式通話)。預設值為 0(停用)。
建議範圍:
- 正式環境: 通知式流程使用
120至300秒。 - 請讓此值高於
maxDurationSeconds,讓一般通話能完成。良好的起始值是maxDurationSeconds + 30–60秒。
Webhook 安全性
當 Gateway 前方有 Proxy 或通道時,Plugin 會重建公開 URL 以進行簽章驗證。這些選項控制信任哪些轉送標頭:允許清單中的轉送標頭主機。
在沒有允許清單的情況下信任轉送標頭。
只有在請求遠端 IP 符合清單時,才信任轉送標頭。
- Twilio 和 Plivo 已啟用 Webhook 重放保護。重放的有效 Webhook 請求會收到確認,但會略過副作用。
- Twilio 對話輪次會在
<Gather>回呼中包含每輪權杖,因此過期/重放的語音回呼無法滿足較新的待處理逐字稿輪次。 - 當缺少提供者要求的簽章標頭時,未驗證的 Webhook 請求會在讀取本文前遭拒。
- voice-call Webhook 會使用共用的預先驗證本文設定檔(64 KB / 5 秒),並在簽章驗證前套用每 IP 進行中請求上限。
CLI
latency 會從預設的 voice-call 儲存路徑讀取 calls.jsonl。使用 --file <path> 指向不同記錄,並使用 --last <n> 將分析限制為最後 N 筆記錄(預設 200)。輸出包含輪次延遲與聆聽等待時間的 p50/p90/p99。
代理工具
工具名稱:voice_call。
| 動作 | 引數 |
|---|---|
initiate_call | message, to?, mode? |
continue_call | callId, message |
speak_to_user | callId, message |
send_dtmf | callId, digits |
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.dtmf | callId, digits |
voicecall.end | callId |
voicecall.status | callId |