Voice Call (plugin)
المكالمات الصوتية في OpenClaw عبر plugin. يدعم الإشعارات الصادرة والمحادثات متعددة الأدوار مع سياسات للمكالمات الواردة. المزوّدون الحاليون:twilio(Programmable Voice + Media Streams)telnyx(Call Control v2)plivo(Voice API + XML transfer + GetInput speech)mock(للتطوير/من دون شبكة)
- ثبّت plugin
- أعد تشغيل Gateway
- هيّئ تحت
plugins.entries.voice-call.config - استخدم
openclaw voicecall ...أو أداةvoice_call
مكان التشغيل (محلي أم بعيد)
يعمل plugin Voice Call داخل عملية Gateway. إذا كنت تستخدم Gateway بعيدًا، فقم بتثبيت/تهيئة plugin على الجهاز الذي يشغّل Gateway، ثم أعد تشغيل Gateway لتحميله.التثبيت
الخيار A: التثبيت من npm (موصى به)
الخيار B: التثبيت من مجلد محلي (للتطوير، من دون نسخ)
الإعدادات
اضبط الإعدادات تحتplugins.entries.voice-call.config:
- يتطلب Twilio/Telnyx عنوان URL لـ webhook قابلًا للوصول علنًا.
- يتطلب Plivo عنوان URL لـ webhook قابلًا للوصول علنًا.
mockهو مزوّد تطوير محلي (من دون استدعاءات شبكة).- إذا كانت الإعدادات الأقدم لا تزال تستخدم
provider: "log"أوtwilio.fromأو مفاتيح OpenAI القديمة فيstreaming.*، فشغّلopenclaw doctor --fixلإعادة كتابتها. - يتطلب Telnyx القيمة
telnyx.publicKey(أوTELNYX_PUBLIC_KEY) ما لم تكنskipSignatureVerificationتساوي true. - إن
skipSignatureVerificationمخصص للاختبار المحلي فقط. - إذا كنت تستخدم الطبقة المجانية من ngrok، فاضبط
publicUrlعلى عنوان URL الدقيق الخاص بـ ngrok؛ إذ يتم فرض التحقق من التوقيع دائمًا. - تسمح
tunnel.allowNgrokFreeTierLoopbackBypass: trueبـ webhooks من Twilio ذات تواقيع غير صالحة فقط عندما يكونtunnel.provider="ngrok"ويكونserve.bindهو loopback (وكيل ngrok المحلي). استخدم ذلك للتطوير المحلي فقط. - قد تتغير عناوين URL الخاصة بالطبقة المجانية من ngrok أو تضيف سلوك interstitial؛ وإذا تغيّر
publicUrl، فستفشل تواقيع Twilio. وللإنتاج، فضّل نطاقًا ثابتًا أو Tailscale funnel. - الإعدادات الافتراضية لأمان البث:
- تقوم
streaming.preStartTimeoutMsبإغلاق المقابس التي لا ترسل مطلقًا إطارstartصالحًا.
- تقوم
- تحد
streaming.maxPendingConnectionsمن إجمالي مقابس ما قبل البدء غير الموثقة. - تحد
streaming.maxPendingConnectionsPerIpمن مقابس ما قبل البدء غير الموثقة لكل عنوان IP مصدر. - تحد
streaming.maxConnectionsمن إجمالي مقابس بث الوسائط المفتوحة (المعلقة + النشطة). - لا يزال التراجع في وقت التشغيل يقبل مفاتيح voice-call القديمة هذه في الوقت الحالي، لكن مسار إعادة الكتابة هو
openclaw doctor --fixوطبقة التوافق مؤقتة.
النسخ الفوري
يحددstreaming مزوّد النسخ الفوري للصوت المباشر للمكالمات.
سلوك وقت التشغيل الحالي:
streaming.providerاختياري. وإذا لم يتم ضبطه، يستخدم Voice Call أول مزوّد نسخ فوري مسجل.- اليوم، المزوّد المضمّن هو OpenAI، والمسجل بواسطة plugin المضمّن
openai. - توجد الإعدادات الخام المملوكة للمزوّد تحت
streaming.providers.<providerId>. - إذا كانت
streaming.providerتشير إلى مزوّد غير مسجل، أو لم يكن هناك أي مزوّد نسخ فوري مسجل أصلًا، يسجل Voice Call تحذيرًا ويتخطى بث الوسائط بدلًا من فشل plugin بالكامل.
- مفتاح API:
streaming.providers.openai.apiKeyأوOPENAI_API_KEY - النموذج:
gpt-4o-transcribe silenceDurationMs: 800vadThreshold: 0.5
openclaw doctor --fix:
streaming.sttProvider→streaming.providerstreaming.openaiApiKey→streaming.providers.openai.apiKeystreaming.sttModel→streaming.providers.openai.modelstreaming.silenceDurationMs→streaming.providers.openai.silenceDurationMsstreaming.vadThreshold→streaming.providers.openai.vadThreshold
منظف المكالمات القديمة
استخدمstaleCallReaperSeconds لإنهاء المكالمات التي لا تتلقى مطلقًا webhook نهائيًا
(على سبيل المثال مكالمات وضع notify التي لا تكتمل أبدًا). القيمة الافتراضية هي 0
(معطل).
النطاقات الموصى بها:
- الإنتاج: من
120إلى300ثانية للتدفقات على نمط notify. - أبقِ هذه القيمة أعلى من
maxDurationSecondsحتى تتمكن المكالمات العادية من الاكتمال. ونقطة بداية جيدة هيmaxDurationSeconds + 30–60ثانية.
أمان Webhook
عندما يكون proxy أو tunnel أمام Gateway، يعيد plugin بناء عنوان URL العام لأغراض التحقق من التوقيع. وتتحكم هذه الخيارات في أي الترويسات المعادة توجيهها يتم الوثوق بها. تضعwebhookSecurity.allowedHosts قائمة سماح بالمضيفين القادمين من ترويسات إعادة التوجيه.
تجعل webhookSecurity.trustForwardingHeaders الثقة بالترويسات المعاد توجيهها ممكنة من دون قائمة سماح.
تجعل webhookSecurity.trustedProxyIPs الثقة بالترويسات المعاد توجيهها ممكنة فقط عندما
يطابق عنوان IP البعيد للطلب القائمة.
تكون حماية إعادة تشغيل webhook مفعلة لـ Twilio وPlivo. وتتم الموافقة على
طلبات webhook المعاد تشغيلها والصحيحة ولكن يتم تخطي آثارها الجانبية.
تتضمن أدوار المحادثة في Twilio رمزًا مميزًا لكل دور في استدعاءات <Gather>، بحيث
لا يمكن لاستدعاءات الكلام القديمة/المعاد تشغيلها أن تلبّي دور نسخ أحدث ما يزال معلقًا.
تُرفض طلبات webhook غير الموثقة قبل قراءة الجسم عندما تكون
ترويسات التوقيع المطلوبة من المزوّد مفقودة.
يستخدم webhook الخاص بـ voice-call ملف تعريف الجسم قبل المصادقة المشترك (64 KB / 5 ثوانٍ)
بالإضافة إلى حد لكل IP للطلبات قيد التنفيذ قبل التحقق من التوقيع.
مثال مع مضيف عام ثابت:
TTS للمكالمات
يستخدم Voice Call إعداداتmessages.tts الأساسية من أجل
بث الكلام في المكالمات. ويمكنك تجاوزها تحت إعدادات plugin باستخدام
البنية نفسها — حيث تُدمج دمجًا عميقًا مع messages.tts.
- تُرحّل مفاتيح
tts.<provider>القديمة داخل إعدادات plugin (openaiوelevenlabsوmicrosoftوedge) تلقائيًا إلىtts.providers.<provider>عند التحميل. فضّل بنيةprovidersفي الإعدادات الملتزم بها. - يتم تجاهل Microsoft speech في المكالمات الصوتية (فالصوت الهاتفي يحتاج إلى PCM؛ أما النقل الحالي لـ Microsoft فلا يكشف خرج PCM الهاتفي).
- يتم استخدام TTS الأساسي عند تمكين Twilio media streaming؛ وإلا تعود المكالمات إلى الأصوات الأصلية للمزوّد.
- إذا كان Twilio media stream نشطًا بالفعل، فلن يعود Voice Call إلى TwiML
<Say>. وإذا لم يكن TTS الهاتفي متاحًا في تلك الحالة، يفشل طلب التشغيل بدلًا من مزج مساري تشغيل. - عندما يعود TTS الهاتفي إلى مزوّد ثانوي، يسجل Voice Call تحذيرًا مع سلسلة المزوّد (
fromوtoوattempts) لأغراض التصحيح.
مزيد من الأمثلة
استخدم TTS الأساسي فقط (من دون تجاوز):المكالمات الواردة
تكون القيمة الافتراضية لسياسة الواردdisabled. ولتمكين المكالمات الواردة، اضبط:
inboundPolicy: "allowlist" هو فحص منخفض الضمان لمعرّف المتصل. يقوم plugin
بتطبيع قيمة From الموردة من المزوّد ويقارنها مع allowFrom.
وتصادق عملية التحقق من webhook على تسليم المزوّد وسلامة الحمولة، لكنها
لا تثبت ملكية رقم المتصل في PSTN/VoIP. لذا تعامل مع allowFrom على
أنه تصفية لمعرّف المتصل، وليس هوية قوية للمتصل.
تستخدم الردود التلقائية نظام الوكيل. ويمكن ضبطها عبر:
responseModelresponseSystemPromptresponseTimeoutMs
عقد الخرج المنطوق
بالنسبة إلى الردود التلقائية، يضيف Voice Call عقد خرج منطوق صارمًا إلى system prompt:{"spoken":"..."}
- يتجاهل الحمولات الموسومة على أنها reasoning/error.
- يحلل JSON المباشر، أو JSON داخل fenced، أو مفاتيح
"spoken"المضمنة. - يعود إلى النص العادي ويزيل فقرات المقدمة التخطيطية/الوصفية المرجحة.
سلوك بدء المحادثة
بالنسبة إلى مكالماتconversation الصادرة، يرتبط التعامل مع أول رسالة بحالة التشغيل المباشر:
- يتم كبت مسح طابور barge-in والرد التلقائي فقط أثناء نطق التحية الأولية فعليًا.
- إذا فشل التشغيل الأولي، تعود المكالمة إلى
listeningوتبقى الرسالة الأولية في الطابور لإعادة المحاولة. - يبدأ التشغيل الأولي للبث في Twilio عند اتصال stream من دون تأخير إضافي.
مهلة سماح فصل بث Twilio
عندما ينفصل Twilio media stream، ينتظر Voice Call مدة2000ms قبل الإنهاء التلقائي للمكالمة:
- إذا أعاد stream الاتصال خلال تلك النافذة، يتم إلغاء الإنهاء التلقائي.
- إذا لم تتم إعادة تسجيل أي stream بعد فترة السماح، يتم إنهاء المكالمة لمنع بقاء مكالمات نشطة عالقة.
CLI
latency الملف calls.jsonl من مسار تخزين voice-call الافتراضي. استخدم
--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)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)