Zum Inhalt springen

OpenClaw Voice Call Plugin: Sprachfunktionen einrichten

Kennst du das? Du willst eigentlich nur eine einfache Sprachbenachrichtigung oder einen KI-Anruf in deine App einbauen, aber plötzlich hängst du knietief in Webhook-Konfigurationen, Latenzproblemen und Provider-spezifischen XML-Dialekten fest. Es ist frustrierend, wenn die Technik dem eigentlichen Feature im Weg steht und du mehr Zeit mit der Infrastruktur als mit der Logik verbringst.

Mit dem Voice Call Plugin für OpenClaw kannst du diesen Prozess massiv abkürzen. Es bietet dir eine saubere Abstraktion für verschiedene Provider und kümmert sich um den schwierigen Teil der Echtzeit-Kommunikation. Hier erfährst du, wie du das Plugin einrichtest und optimal nutzt.

Voice Calls für OpenClaw über ein Plugin. Unterstützt Outbound-Benachrichtigungen und Multi-Turn-Konversationen mit Inbound-Policies.

Aktuelle Provider:

  • twilio (Programmable Voice + Media Streams)
  • telnyx (Call Control v2)
  • plivo (Voice API + XML transfer + GetInput speech)
  • mock (Dev/kein Netzwerk)

Kurzes mentales Modell:

  • Plugin installieren
  • Gateway neu starten
  • Unter plugins.entries.voice-call.config konfigurieren
  • openclaw voicecall ... oder das voice_call Tool verwenden

Das Voice Call Plugin läuft innerhalb des Gateway-Prozesses.

Wenn du ein remote Gateway verwendest, installiere und konfiguriere das Plugin auf der Maschine, auf der das Gateway läuft, und starte das Gateway neu, um es zu laden.

Terminal-Fenster
openclaw plugins install @openclaw/voice-call

Starte das Gateway danach neu.

Option B: Aus einem lokalen Ordner installieren (Dev, kein Kopieren)

Abschnitt betitelt „Option B: Aus einem lokalen Ordner installieren (Dev, kein Kopieren)“
Terminal-Fenster
PLUGIN_SRC=./path/to/local/voice-call-plugin
openclaw plugins install "$PLUGIN_SRC"
cd "$PLUGIN_SRC" && pnpm install

Starte das Gateway danach neu.

Setze die Konfiguration unter plugins.entries.voice-call.config:

{
plugins: {
entries: {
"voice-call": {
enabled: true,
config: {
provider: "twilio", // or "telnyx" | "plivo" | "mock"
fromNumber: "+15550001234",
toNumber: "+15550005678",
twilio: {
accountSid: "ACxxxxxxxx",
authToken: "...",
},
telnyx: {
apiKey: "...",
connectionId: "...",
// Telnyx webhook public key from the Telnyx Mission Control Portal
// (Base64 string; can also be set via TELNYX_PUBLIC_KEY).
publicKey: "...",
},
plivo: {
authId: "MAxxxxxxxxxxxxxxxxxxxx",
authToken: "...",
},
// Webhook server
serve: {
port: 3334,
path: "/voice/webhook",
},
// Webhook security (recommended for tunnels/proxies)
webhookSecurity: {
allowedHosts: ["voice.example.com"],
trustedProxyIPs: ["100.64.0.1"],
},
// Public exposure (pick one)
// 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 benötigen eine öffentlich erreichbare Webhook-URL.
  • Plivo benötigt eine öffentlich erreichbare Webhook-URL.
  • mock ist ein lokaler Dev-Provider (keine Netzwerkaufrufe).
  • Telnyx erfordert telnyx.publicKey (oder TELNYX_PUBLIC_KEY), außer skipSignatureVerification ist auf true gesetzt.
  • skipSignatureVerification ist nur für lokales Testen gedacht.
  • Wenn du den kostenlosen ngrok-Tarif nutzt, setze publicUrl auf die exakte ngrok-URL; die Signaturprüfung wird immer erzwungen.
  • tunnel.allowNgrokFreeTierLoopbackBypass: true erlaubt Twilio-Webhooks mit ungültigen Signaturen nur, wenn tunnel.provider="ngrok" und serve.bind auf Loopback (lokaler ngrok-Agent) steht. Nur für lokale Entwicklung nutzen.
  • URLs im kostenlosen ngrok-Tarif können sich ändern oder Interstitial-Seiten anzeigen; wenn publicUrl abweicht, schlagen Twilio-Signaturen fehl. Für die Produktion solltest du eine stabile Domain oder einen Tailscale Funnel bevorzugen.
  • Standardwerte für die Streaming-Sicherheit:
    • streaming.preStartTimeoutMs schließt Sockets, die nie einen gültigen start-Frame senden.
    • streaming.maxPendingConnections begrenzt die Gesamtzahl der nicht authentifizierten Pre-Start-Sockets.
    • streaming.maxPendingConnectionsPerIp begrenzt diese pro Quell-IP.
    • streaming.maxConnections begrenzt die Gesamtzahl der offenen Media-Stream-Sockets (ausstehend + aktiv).

Nutze staleCallReaperSeconds, um Anrufe zu beenden, die nie einen finalen Webhook erhalten (zum Beispiel Anrufe im Notify-Modus, die nie abgeschlossen werden). Der Standardwert ist 0 (deaktiviert).

Empfohlene Bereiche:

  • Produktion: 120–300 Sekunden für Notify-Flows.
  • Halte diesen Wert höher als maxDurationSeconds, damit normale Anrufe beendet werden können. Ein guter Startpunkt ist maxDurationSeconds + 30–60 Sekunden.

Beispiel:

{
plugins: {
entries: {
"voice-call": {
config: {
maxDurationSeconds: 300,
staleCallReaperSeconds: 360,
},
},
},
},
}

Wenn ein Proxy oder Tunnel vor dem Gateway sitzt, rekonstruiert das Plugin die öffentliche URL für die Signaturprüfung. Diese Optionen steuern, welchen Forwarded-Headern vertraut wird.

webhookSecurity.allowedHosts erlaubt Hosts aus Forwarding-Headern per Allowlist.

webhookSecurity.trustForwardingHeaders vertraut Forwarded-Headern ohne Allowlist.

webhookSecurity.trustedProxyIPs vertraut Forwarded-Headern nur, wenn die Remote-IP des Requests mit der Liste übereinstimmt.

Ein Webhook-Replay-Schutz ist für Twilio und Plivo aktiviert. Erneute gültige Webhook-Anfragen werden bestätigt, aber für Seiteneffekte übersprungen.

Twilio-Konversationsrunden enthalten ein Token pro Runde in <Gather>-Callbacks, sodass veraltete oder wiederholte Speech-Callbacks keine neuere ausstehende Transkriptionsrunde erfüllen können.

Nicht authentifizierte Webhook-Anfragen werden abgelehnt, bevor der Body gelesen wird, wenn die erforderlichen Signatur-Header des Providers fehlen.

Der Voice-Call-Webhook nutzt das gemeinsame Pre-Auth-Body-Profil (64 KB / 5 Sekunden) sowie ein Limit für aktive Anfragen pro IP vor der Signaturprüfung.

Beispiel mit einem stabilen öffentlichen Host:

{
plugins: {
entries: {
"voice-call": {
config: {
publicUrl: "https://voice.example.com/voice/webhook",
webhookSecurity: {
allowedHosts: ["voice.example.com"],
},
},
},
},
},
}

Voice Call nutzt die zentrale messages.tts Konfiguration für Streaming-Sprache bei Anrufen. Du kannst dies unter der Plugin-Konfiguration mit der gleichen Struktur überschreiben – es wird per Deep-Merge mit messages.tts zusammengeführt.

{
tts: {
provider: "elevenlabs",
providers: {
elevenlabs: {
voiceId: "pMsXgVXv3BLzUgSXRplE",
modelId: "eleven_multilingual_v2",
},
},
},
}

Hinweise:

  • Veraltete tts.<provider> Keys innerhalb der Plugin-Konfiguration (openai, elevenlabs, microsoft, edge) werden beim Laden automatisch nach tts.providers.<provider> migriert. Bevorzuge die providers-Struktur in deiner Konfiguration.
  • Microsoft Speech wird für Voice Calls ignoriert (Telefonie-Audio benötigt PCM; der aktuelle Microsoft-Transport stellt keinen Telefonie-PCM-Output bereit).
  • Core TTS wird verwendet, wenn Twilio Media Streaming aktiviert ist; andernfalls fallen Anrufe auf die nativen Stimmen der Provider zurück.
  • Wenn ein Twilio Media Stream bereits aktiv ist, nutzt Voice Call kein Fallback auf TwiML <Say>. Wenn Telefonie-TTS in diesem Zustand nicht verfügbar ist, schlägt die Wiedergabeanfrage fehl, anstatt zwei Wiedergabepfade zu mischen.
  • Wenn Telefonie-TTS auf einen sekundären Provider zurückfällt, loggt Voice Call eine Warnung mit der Provider-Kette (from, to, attempts) für das Debugging.

Nur Core TTS nutzen (kein Override):

{
messages: {
tts: {
provider: "openai",
providers: {
openai: { voice: "alloy" },
},
},
},
}

Override auf ElevenLabs nur für Anrufe (Core-Default ansonsten beibehalten):

{
plugins: {
entries: {
"voice-call": {
config: {
tts: {
provider: "elevenlabs",
providers: {
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: {
providers: {
openai: {
model: "gpt-4o-mini-tts",
voice: "marin",
},
},
},
},
},
},
},
}

Die Inbound-Policy steht standardmäßig auf disabled. Um eingehende Anrufe zu aktivieren, setze:

{
inboundPolicy: "allowlist",
allowFrom: ["+15550001234"],
inboundGreeting: "Hello! How can I help?",
}

inboundPolicy: "allowlist" ist eine einfache Caller-ID-Prüfung. Das Plugin normalisiert den vom Provider gelieferten From-Wert und vergleicht ihn mit allowFrom. Die Webhook-Verifizierung authentifiziert die Zustellung durch den Provider und die Integrität der Daten, beweist aber nicht den Besitz der PSTN/VoIP-Rufnummer durch den Anrufer. Betrachte allowFrom als Caller-ID-Filterung, nicht als starke Identitätsprüfung.

Auto-Responses nutzen das Agent-System. Optimiere dies mit:

  • responseModel
  • responseSystemPrompt
  • responseTimeoutMs

Für Auto-Responses fügt Voice Call einen strikten Spoken-Output-Contract an den System-Prompt an:

  • {"spoken":"..."}

Voice Call extrahiert den Sprachtext dann defensiv:

  • Ignoriert Payloads, die als Reasoning- oder Error-Content markiert sind.
  • Parst direktes JSON, Fenced JSON oder Inline-"spoken"-Keys.
  • Fällt auf Plain Text zurück und entfernt wahrscheinliche Planungs- oder Meta-Einleitungen.

Dies hält die Sprachwiedergabe auf den für den Anrufer relevanten Text fokussiert und verhindert, dass interne Planungstexte im Audio landen.

Bei Outbound-conversation-Anrufen ist die Verarbeitung der ersten Nachricht an den Live-Wiedergabestatus gebunden:

  • Die Barge-in-Queue-Leerung und die Auto-Response werden nur unterdrückt, während die initiale Begrüßung aktiv gesprochen wird.
  • Wenn die initiale Wiedergabe fehlschlägt, kehrt der Anruf zu listening zurück und die initiale Nachricht bleibt für einen erneuten Versuch in der Warteschlange.
  • Die initiale Wiedergabe für Twilio-Streaming startet bei Stream-Verbindung ohne zusätzliche Verzögerung.

Wenn ein Twilio Media Stream die Verbindung verliert, wartet Voice Call 2000ms, bevor der Anruf automatisch beendet wird:

  • Wenn der Stream innerhalb dieses Fensters die Verbindung wiederherstellt, wird das automatische Beenden abgebrochen.
  • Wenn nach der Grace Period kein Stream neu registriert wurde, wird der Anruf beendet, um hängende aktive Anrufe zu vermeiden.
Terminal-Fenster
openclaw voicecall call --to "+15555550123" --message "Hello from OpenClaw"
openclaw voicecall start --to "+15555550123" # alias for call
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 latency # summarize turn latency from logs
openclaw voicecall expose --mode funnel

latency liest calls.jsonl aus dem Standard-Speicherpfad von Voice Call. Nutze --file <path>, um auf ein anderes Log zu verweisen, und --last <n>, um die Analyse auf die letzten N Datensätze zu begrenzen (Standard 200). Die Ausgabe enthält p50/p90/p99 für Turn-Latenz und Listen-Wait-Zeiten.

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 Repo enthält ein passendes Skill-Dokument unter skills/voice-call/SKILL.md.

  • voicecall.initiate (to?, message, mode?)
  • voicecall.continue (callId, message)
  • voicecall.speak (callId, message)
  • voicecall.end (callId)
  • voicecall.status (callId)

Hast du Fragen zur Einrichtung? Frag den AI Setup Assistant.

OpenClaw

OpenClaw Expert

Noch festgefahren?

Wenn diese Seite nicht hilft, frage OpenClaw Expert nach Schritt-fuer-Schritt-Loesungen.