Voice Call (Plugin)
Sprachanrufe für OpenClaw über ein Plugin. Unterstützt ausgehende Benachrichtigungen und Multi-Turn-Konversationen mit Richtlinien für eingehende Anrufe.
Aktuelle Provider:
twilio(Programmable Voice + Media Streams)telnyx(Call Control v2)plivo(Voice API + XML Transfer + GetInput Speech)mock(Entwicklung/ohne Netzwerk)
Kurzmodell:
- Plugin installieren
- Gateway neu starten
- Unter
plugins.entries.voice-call.configkonfigurieren openclaw voicecall ...oder dasvoice_call-Tool nutzen
Wo es läuft (lokal vs. remote)
Das Voice-Call-Plugin läuft innerhalb des Gateway-Prozesses.
Wenn du ein Remote-Gateway nutzt, installiere/konfiguriere das Plugin auf dem Rechner, auf dem das Gateway läuft, und starte dann das Gateway neu, um es zu laden.
Installation
Option A: Aus npm installieren (empfohlen)
openclaw plugins install @openclaw/voice-call
Starte das Gateway danach neu.
Option B: Aus einem lokalen Ordner installieren (Entwicklung, ohne Kopieren)
openclaw plugins install ./extensions/voice-call
cd ./extensions/voice-call && pnpm install
Starte das Gateway danach neu.
Konfiguration
Konfiguration unter plugins.entries.voice-call.config setzen:
{
plugins: {
entries: {
"voice-call": {
enabled: true,
config: {
provider: "twilio", // oder "telnyx" | "plivo" | "mock"
fromNumber: "+15550001234",
toNumber: "+15550005678",
twilio: {
accountSid: "ACxxxxxxxx",
authToken: "...",
},
telnyx: {
apiKey: "...",
connectionId: "...",
// Telnyx-Webhook-Public-Key aus dem Telnyx Mission Control Portal
// (Base64-String; kann auch über TELNYX_PUBLIC_KEY gesetzt werden).
publicKey: "...",
},
plivo: {
authId: "MAxxxxxxxxxxxxxxxxxxxx",
authToken: "...",
},
// Webhook-Server
serve: {
port: 3334,
path: "/voice/webhook",
},
// Webhook-Sicherheit (empfohlen für Tunnel/Proxies)
webhookSecurity: {
allowedHosts: ["voice.example.com"],
trustedProxyIPs: ["100.64.0.1"],
},
// Öffentliche Erreichbarkeit (wähle eine)
// 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,
},
},
},
},
},
}
Hinweise:
- Twilio/Telnyx erfordern eine öffentlich erreichbare Webhook-URL.
- Plivo erfordert eine öffentlich erreichbare Webhook-URL.
mockist ein lokaler Entwicklungs-Provider (keine Netzwerkaufrufe).- Telnyx erfordert
telnyx.publicKey(oderTELNYX_PUBLIC_KEY), es sei dennskipSignatureVerificationist true. skipSignatureVerificationist nur für lokales Testen gedacht.- Wenn du den kostenlosen ngrok-Tarif nutzt, setze
publicUrlauf die exakte ngrok-URL; Signaturverifizierung wird immer durchgesetzt. tunnel.allowNgrokFreeTierLoopbackBypass: trueerlaubt Twilio-Webhooks mit ungültigen Signaturen nur wenntunnel.provider="ngrok"undserve.bindLoopback ist (ngrok Local Agent). Nur für lokale Entwicklung verwenden.- Kostenlose ngrok-Tier-URLs können sich ändern oder Interstitial-Verhalten hinzufügen; wenn
publicUrlabweicht, schlagen Twilio-Signaturen fehl. Für Produktion bevorzuge eine stabile Domain oder Tailscale Funnel. - Standard-Streaming-Sicherheit:
streaming.preStartTimeoutMsschließt Sockets, die nie einen gültigenstart-Frame senden.streaming.maxPendingConnectionsbegrenzt nicht authentifizierte Pre-Start-Sockets insgesamt.streaming.maxPendingConnectionsPerIpbegrenzt nicht authentifizierte Pre-Start-Sockets pro Quell-IP.streaming.maxConnectionsbegrenzt die Gesamtzahl offener Media-Stream-Sockets (ausstehend + aktiv).
Bereinigung veralteter Anrufe
Nutze staleCallReaperSeconds, um Anrufe zu beenden, die nie einen finalen Webhook erhalten
(zum Beispiel Notify-Modus-Anrufe, die nie abschließen). Standard ist 0
(deaktiviert).
Empfohlene Bereiche:
- Produktion:
120–300Sekunden für Notify-artige Flows. - Halte diesen Wert höher als
maxDurationSeconds, damit normale Anrufe abgeschlossen werden können. Ein guter Startpunkt istmaxDurationSeconds + 30–60Sekunden.
Beispiel:
{
plugins: {
entries: {
"voice-call": {
config: {
maxDurationSeconds: 300,
staleCallReaperSeconds: 360,
},
},
},
},
}
Webhook-Sicherheit
Wenn ein Proxy oder Tunnel vor dem Gateway sitzt, rekonstruiert das Plugin die öffentliche URL für die Signaturverifizierung. Diese Optionen steuern, welchen weitergeleiteten Headern vertraut wird.
webhookSecurity.allowedHosts erlaubt Hosts aus Weiterleitungs-Headern.
webhookSecurity.trustForwardingHeaders vertraut weitergeleiteten Headern ohne Allowlist.
webhookSecurity.trustedProxyIPs vertraut weitergeleiteten Headern nur, wenn die Remote-IP der Anfrage
in der Liste enthalten ist.
Webhook-Replay-Schutz ist für Twilio und Plivo aktiviert. Wiederholte gültige Webhook- Anfragen werden bestätigt, aber für Seiteneffekte übersprungen.
Twilio-Konversations-Turns enthalten ein Turn-spezifisches Token in <Gather>-Callbacks, sodass
veraltete/wiederholte Sprach-Callbacks keinen neueren ausstehenden Transkript-Turn erfüllen können.
Beispiel mit einem stabilen öffentlichen Host:
{
plugins: {
entries: {
"voice-call": {
config: {
publicUrl: "https://voice.example.com/voice/webhook",
webhookSecurity: {
allowedHosts: ["voice.example.com"],
},
},
},
},
},
}
TTS für Anrufe
Voice Call nutzt die Core-messages.tts-Konfiguration (OpenAI oder ElevenLabs) für
Streaming-Sprache bei Anrufen. Du kannst sie unter der Plugin-Konfiguration mit der
gleichen Struktur überschreiben — sie wird per Deep-Merge mit messages.tts zusammengeführt.
{
tts: {
provider: "elevenlabs",
elevenlabs: {
voiceId: "pMsXgVXv3BLzUgSXRplE",
modelId: "eleven_multilingual_v2",
},
},
}
Hinweise:
- Edge TTS wird für Sprachanrufe ignoriert (Telefonie-Audio braucht PCM; Edge-Ausgabe ist unzuverlässig).
- Core-TTS wird verwendet, wenn Twilio Media Streaming aktiviert ist; sonst fallen Anrufe auf native Provider-Stimmen zurück.
Weitere Beispiele
Nur Core-TTS verwenden (kein Override):
{
messages: {
tts: {
provider: "openai",
openai: { voice: "alloy" },
},
},
}
Nur für Anrufe auf ElevenLabs überschreiben (Core-Standard anderswo beibehalten):
{
plugins: {
entries: {
"voice-call": {
config: {
tts: {
provider: "elevenlabs",
elevenlabs: {
apiKey: "elevenlabs_key",
voiceId: "pMsXgVXv3BLzUgSXRplE",
modelId: "eleven_multilingual_v2",
},
},
},
},
},
},
}
Nur das OpenAI-Modell für Anrufe überschreiben (Deep-Merge-Beispiel):
{
plugins: {
entries: {
"voice-call": {
config: {
tts: {
openai: {
model: "gpt-4o-mini-tts",
voice: "marin",
},
},
},
},
},
},
}
Eingehende Anrufe
Die Richtlinie für eingehende Anrufe ist standardmäßig disabled. Um eingehende Anrufe zu aktivieren, setze:
{
inboundPolicy: "allowlist",
allowFrom: ["+15550001234"],
inboundGreeting: "Hello! How can I help?",
}
inboundPolicy: "allowlist" ist eine Anrufer-ID-Prüfung mit geringer Sicherheit. Das Plugin
normalisiert den vom Provider gelieferten From-Wert und vergleicht ihn mit allowFrom.
Webhook-Verifizierung authentifiziert Provider-Zustellung und Payload-Integrität, beweist aber
nicht PSTN/VoIP-Rufnummern-Besitz. Behandle allowFrom als
Anrufer-ID-Filterung, nicht als starke Identitätsprüfung.
Auto-Antworten nutzen das Agent-System. Feinjustierung über:
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
Agent-Tool
Tool-Name: voice_call
Aktionen:
initiate_call(message, to?, mode?)continue_call(callId, message)speak_to_user(callId, message)end_call(callId)get_status(callId)
Dieses Repository liefert ein passendes Skill-Dokument unter 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)