Mainstream messaging

WhatsApp

وضعیت: آمادهٔ استفاده در محیط تولید از طریق WhatsApp Web (Baileys). Gateway مالک نشست‌های پیوندشده است؛ کانال جداگانه‌ای برای Twilio WhatsApp وجود ندارد.

نصب

openclaw onboard و openclaw channels add --channel whatsapp نخستین باری که آن را انتخاب می‌کنید، نصب Plugin را پیشنهاد می‌کنند؛ اگر Plugin موجود نباشد، openclaw channels login --channel whatsapp نیز همان فرایند نصب را ارائه می‌دهد. نسخه‌های توسعه از مسیر محلی Plugin استفاده می‌کنند؛ نصب‌های پایدار/بتا ابتدا @openclaw/whatsapp را از ClawHub نصب می‌کنند و در صورت ناموفق‌بودن به npm برمی‌گردند. زمان‌اجرای WhatsApp خارج از بستهٔ اصلی npm مربوط به OpenClaw عرضه می‌شود، بنابراین وابستگی‌های زمان‌اجرای آن همراه Plugin خارجی باقی می‌مانند. نصب دستی:

bash
openclaw plugins install clawhub:@openclaw/whatsapp

بستهٔ سادهٔ npm (@openclaw/whatsapp) را فقط برای بازگشت به رجیستری استفاده کنید؛ نسخه‌ای دقیق را فقط برای نصب تکرارپذیر پین کنید.

راه‌اندازی سریع

  • پیکربندی سیاست دسترسی

    json5
    {channels: {whatsapp: {  dmPolicy: "pairing",  allowFrom: ["+15551234567"],  groupPolicy: "allowlist",  groupAllowFrom: ["+15551234567"],},},}
  • پیوند WhatsApp ‏(QR)

    bash
    openclaw channels login --channel whatsapp

    ورود فقط از طریق QR انجام می‌شود. در میزبان‌های راه‌دور یا بدون نمایشگر، پیش از آغاز ورود، روشی قابل‌اعتماد برای رساندن QR زنده به تلفن فراهم کنید؛ QRهای نمایش‌داده‌شده در ترمینال، اسکرین‌شات‌ها یا پیوست‌های چت ممکن است هنگام انتقال منقضی شوند.

    برای حسابی مشخص:

    bash
    openclaw channels login --channel whatsapp --account work

    برای پیوست‌کردن پوشهٔ احراز هویت موجود/سفارشی پیش از ورود:

    bash
    openclaw channels add --channel whatsapp --account work --auth-dir /path/to/wa-authopenclaw channels login --channel whatsapp --account work
  • راه‌اندازی Gateway

    bash
    openclaw gateway
  • تأیید نخستین درخواست جفت‌سازی (حالت جفت‌سازی)

    bash
    openclaw pairing list whatsappopenclaw pairing approve whatsapp <CODE>

    درخواست‌های جفت‌سازی پس از 1 ساعت منقضی می‌شوند؛ تعداد درخواست‌های در انتظار برای هر حساب حداکثر 3 مورد است.

  • الگوهای استقرار

    شمارهٔ اختصاصی (توصیه‌شده)
    • هویت جداگانهٔ WhatsApp برای OpenClaw
    • فهرست‌های مجاز پیام مستقیم و مرزهای مسیریابی شفاف‌تر
    • احتمال کمتر سردرگمی در گفت‌وگو با خود
    json5
    {  channels: {    whatsapp: {      dmPolicy: "allowlist",      allowFrom: ["+15551234567"],    },  },}
    گزینهٔ جایگزین با شمارهٔ شخصی

    فرایند آغاز به کار از حالت شمارهٔ شخصی پشتیبانی می‌کند و یک خط‌مبنای سازگار با گفت‌وگو با خود می‌نویسد: dmPolicy: "allowlist"، allowFrom شامل شمارهٔ خودتان، selfChatMode: true. محافظت‌های زمان‌اجرا برای گفت‌وگو با خود بر اساس شمارهٔ خودِ پیوندشده به‌همراه allowFrom عمل می‌کنند.

    مدل زمان‌اجرا

    • Gateway مالک سوکت WhatsApp و حلقهٔ اتصال مجدد است.
    • یک نگهبان دو سیگنال را مستقل از یکدیگر ردیابی می‌کند: فعالیت خام انتقال WhatsApp Web و فعالیت پیام‌های برنامه. نشست ساکت اما متصل صرفاً به‌دلیل نرسیدن پیام در زمان اخیر راه‌اندازی مجدد نمی‌شود؛ اتصال مجدد فقط زمانی اجباری می‌شود که فریم‌های انتقال برای یک بازهٔ داخلی ثابت (غیرقابل‌پیکربندی توسط کاربر) نرسند یا پیام‌های برنامه برای مدتی بیش از 4 برابر مهلت عادی پیام ساکت بمانند. بلافاصله پس از اتصال مجدد یک نشست که اخیراً فعال بوده است، نخستین بازه به‌جای بازهٔ 4 برابری از مهلت کوتاه‌تر و عادی پیام استفاده می‌کند. OpenClaw می‌تواند به پیام‌های آفلاینی که Baileys در اوایل آن اتصال مجدد تحویل می‌دهد، به‌طور خودکار پاسخ دهد؛ این رفتار به طول عمر حذف تکرار شناسهٔ پیام ورودی محدود است. راه‌اندازی اولیه محافظ کوتاه سابقهٔ کهنه را حفظ می‌کند.
    • زمان‌بندی‌های سوکت Baileys به‌صراحت زیر web.whatsapp.* تعریف شده‌اند: keepAliveIntervalMs (فاصلهٔ پینگ برنامه)، connectTimeoutMs (مهلت دست‌دهی آغازین)، defaultQueryTimeoutMs (انتظار برای پرس‌وجوهای Baileys، به‌علاوهٔ مهلت‌های ارسال/حضور خروجی و رسید خواندن ورودی OpenClaw).
    • ارسال‌های خروجی به شنوندهٔ فعال WhatsApp برای حساب مقصد نیاز دارند؛ در غیر این صورت ارسال‌ها فوراً ناموفق می‌شوند.
    • ارسال‌های گروهی برای توکن‌های @+<digits> و @<digits> (در متن و شرح رسانه) فرادادهٔ بومی اشاره را پیوست می‌کنند، مشروط بر اینکه توکن با فرادادهٔ فعلی مشارکت‌کننده مطابقت داشته باشد؛ این شامل گروه‌های مبتنی بر LID نیز می‌شود.
    • گفت‌وگوهای وضعیت و پخش همگانی (@status، @broadcast) نادیده گرفته می‌شوند.
    • گفت‌وگوهای مستقیم از قواعد نشست پیام مستقیم استفاده می‌کنند (session.dmScope؛ مقدار پیش‌فرض main پیام‌های مستقیم را در نشست اصلی عامل ادغام می‌کند). نشست‌های گروهی برای هر JID جدا هستند (agent:<agentId>:whatsapp:group:<jid>).
    • کانال‌ها/خبرنامه‌های WhatsApp می‌توانند از طریق JID بومی @newsletter خود، مقصد خروجی صریح باشند و به‌جای معنای پیام مستقیم از فرادادهٔ نشست کانال (agent:<agentId>:whatsapp:channel:<jid>) استفاده کنند.
    • انتقال WhatsApp Web متغیرهای محیطی استاندارد پراکسی را در میزبان Gateway رعایت می‌کند (HTTPS_PROXY، HTTP_PROXY، NO_PROXY و گونه‌های حروف کوچک). پیکربندی پراکسی در سطح میزبان را بر تنظیمات هر کانال ترجیح دهید.
    • هنگامی که messages.removeAckAfterReply فعال باشد، OpenClaw پس از تحویل پاسخ قابل‌مشاهده، واکنش تأیید دریافت را پاک می‌کند.

    تماس با درخواست‌کنندهٔ فعلی با MeowCaller (آزمایشی)

    Plugin می‌تواند whatsapp_call را در نوبت‌های عامل منشأگرفته از WhatsApp ارائه کند. این قابلیت با استفاده از MeowCaller یک تماس صوتی WhatsApp با درخواست‌کنندهٔ مجاز فعلی برقرار می‌کند و پس از پاسخ‌دادن او، پیام TTS مربوط به OpenClaw را پخش می‌کند. ابزار پارامتری برای شمارهٔ مقصد ندارد، بنابراین اعلان نمی‌تواند تماس را به مقصد دیگری هدایت کند. به‌طور پیش‌فرض غیرفعال است.

  • فعال‌سازی تماس‌های آزمایشی

    actions.calls: true را به پیکربندی کانال WhatsApp اضافه کنید و Gateway را مجدداً راه‌اندازی کنید:

    json
    {"channels": {"whatsapp": {  "actions": {    "calls": true  }}}}

    در صورت نبودن یا false بودن آن، OpenClaw ابزار whatsapp_call را ارائه نمی‌کند.

  • نصب CLI بازبینی‌شدهٔ MeowCaller

    سازگارگر انتظار دارد فایل اجرایی meowcaller در PATH میزبان Gateway موجود باشد. تا زمان ادغام MeowCaller PR #7، شاخهٔ بازبینی‌شده را بسازید:

    bash
    git clone --branch feat/send-only-notify https://github.com/steipete/meowcaller.gitcd meowcallergit checkout 752050471fc2bf7a8cdfbf7dbd3cd4e865d85d3fmkdir -p "$HOME/.local/bin"go build -o "$HOME/.local/bin/meowcaller" ./cmd/meowcaller

    مطمئن شوید $HOME/.local/bin در PATH سرویس Gateway قرار دارد. این بازبینی فرمان‌های صریح pair و فقط‌ارسال notify را دارد؛ notify هیچ میکروفون، بلندگو، دستگاه ویدئویی یا ضبط تشخیصی را باز نمی‌کند. آن را با فرمان play در CLI نمونهٔ بالادستی جایگزین نکنید.

  • جفت‌سازی دستگاه پیوندشدهٔ MeowCaller

    از عامل WhatsApp بخواهید تنظیمات تماس را بررسی کند (کنش وضعیت whatsapp_call پوشهٔ وضعیت ویژهٔ حساب و فرمان جفت‌سازی را گزارش می‌کند). برای حساب پیش‌فرض:

    bash
    state_dir="$HOME/.openclaw/credentials/whatsapp-calls/default"mkdir -p "$state_dir"chmod 700 "$state_dir"meowcaller pair --store "$state_dir/wa-voip.db"

    این فرمان را به‌صورت تعاملی اجرا کنید، QR را از WhatsApp > Linked devices اسکن کنید و منتظر MeowCaller linked device ready بمانید. wa-voip.db را خصوصی نگه دارید؛ این نشست MeowCaller است. حساب‌های غیراصلی مسیر ذخیره‌سازی خود را از کنش وضعیت دریافت می‌کنند؛ در Windows، فرمان PowerShell آن را اجرا کنید.

  • پیکربندی TTS و تماس از WhatsApp

    یک ارائه‌دهندهٔ TTS با قابلیت تلفنی پیکربندی کنید، Gateway را مجدداً راه‌اندازی کنید و سپس درخواستی مانند Call me and say the build finished. ارسال کنید. ابزار، فرستنده را از زمینهٔ ورودی مورداعتماد تشخیص می‌دهد، یک فایل WAV خصوصی و موقت تولید می‌کند، MeowCaller را برای یک بازهٔ محدود تماس اجرا می‌کند و سپس فایل صوتی را حذف می‌کند. OpenClaw محل ذخیرهٔ حساب را به‌صراحت ارسال می‌کند، پس از پاسخ/پخش/قطع تماس منتظر وضعیت خروج صفر می‌ماند و پایان مهلت یا خروج غیرصفر را تماس ابزار ناموفق در نظر می‌گیرد.

  • محدودیت‌ها: فقط تماس‌های صوتی خروجی یک‌به‌یک، بدون شماره‌های مقصد دلخواه، بدون احراز هویت مشترک با اتصال چت، بدون تماس با خود در حالت شمارهٔ شخصی/گفت‌وگو با خود، صدای تولیدشده با سقف 60 ثانیه، بدون رسید شنیده‌شدن در سمت گوشی فراتر از تکمیل پاسخ/پخش/قطع تماس MeowCaller، و OpenClaw فرایند همراه را پس از بازهٔ محدود 115-175 ثانیه‌ای متوقف می‌کند (که مراحل اتصال، پاسخ، پخش و خاموش‌شدن MeowCaller را پوشش می‌دهد).

    اعلان‌های تأیید

    WhatsApp می‌تواند اعلان‌های تأیید اجرا و Plugin را به‌شکل واکنش‌های 👍/👎 نمایش دهد که پیکربندی سطح‌بالای هدایت تأییدها آن‌ها را کنترل می‌کند:

    json5
    {  approvals: {    exec: {      enabled: true,      mode: "session",    },    plugin: {      enabled: true,      mode: "targets",      targets: [{ channel: "whatsapp", to: "+15551234567" }],    },  },}

    approvals.exec و approvals.plugin مستقل از یکدیگر هستند؛ فعال‌کردن WhatsApp به‌عنوان کانال فقط انتقال را پیوند می‌دهد و تا زمانی که خانوادهٔ تأیید متناظر فعال و به آنجا مسیریابی نشود، چیزی ارسال نمی‌کند. حالت نشست، تأییدهای بومی ایموجی را فقط برای تأییدهایی تحویل می‌دهد که از WhatsApp سرچشمه می‌گیرند. حالت مقصد برای مقصدهای صریح از خط لولهٔ هدایت مشترک استفاده می‌کند و ارسال گستردهٔ جداگانه‌ای به پیام‌های مستقیم تأییدکنندگان ایجاد نمی‌کند.

    واکنش‌های تأیید WhatsApp به تأییدکنندگان صریح در allowFrom (یا "*") نیاز دارند. defaultTo مقصدهای عادی و پیش‌فرض پیام را تعیین می‌کند، نه فهرست تأییدکنندگان را. فرمان‌های دستی /approve همچنان پیش از حل تأیید از مسیر عادی مجوزدهی فرستندهٔ WhatsApp عبور می‌کنند.

    قلاب‌های Plugin و حریم خصوصی

    پیام‌های ورودی WhatsApp ممکن است شامل محتوای شخصی، شماره‌های تلفن، شناسه‌های گروه، نام فرستندگان و فیلدهای هم‌بستگی نشست باشند. WhatsApp بارهای دادهٔ قلاب ورودی message_received را برای Pluginها پخش نمی‌کند، مگر اینکه آن را فعال کنید:

    json5
    {  channels: {    whatsapp: {      pluginHooks: {        messageReceived: true,      },    },  },}

    فعال‌سازی را زیر channels.whatsapp.accounts.<id>.pluginHooks.messageReceived به یک حساب محدود کنید. این قابلیت را فقط برای Pluginهایی فعال کنید که برای دسترسی به محتوا و شناسه‌های ورودی WhatsApp به آن‌ها اعتماد دارید.

    کنترل دسترسی و فعال‌سازی

    سیاست پیام مستقیم

    channels.whatsapp.dmPolicy:

    مقدار رفتار
    pairing (پیش‌فرض) فرستندگان ناشناس درخواست جفت‌سازی می‌کنند؛ مالک تأیید می‌کند
    allowlist فقط فرستندگان allowFrom پذیرفته می‌شوند
    open لازم است allowFrom شامل "*" باشد
    disabled مسدودکردن همهٔ پیام‌های مستقیم

    allowFrom شماره‌هایی به سبک E.164 را می‌پذیرد (که به‌صورت داخلی نرمال‌سازی می‌شوند). این فقط فهرست کنترل دسترسی فرستندگان پیام مستقیم است و ارسال‌های خروجی صریح به JIDهای گروه یا JIDهای کانال @newsletter را محدود نمی‌کند.

    بازنویسی چندحسابی: channels.whatsapp.accounts.<id>.dmPolicy.allowFrom) برای آن حساب بر مقادیر پیش‌فرض سطح کانال اولویت دارند.

    نکات زمان‌اجرا:

    • جفت‌سازی‌ها در ذخیره‌گاه مجاز کانال پایدار می‌مانند و با allowFrom پیکربندی‌شده ادغام می‌شوند
    • اتوماسیون زمان‌بندی‌شده و سازوکار جایگزین گیرنده Heartbeat از مقصدهای تحویل صریح یا allowFrom پیکربندی‌شده استفاده می‌کنند؛ تأییدهای جفت‌سازی پیام خصوصی به‌طور ضمنی گیرنده Cron/Heartbeat نیستند
    • اگر هیچ فهرست مجازی پیکربندی نشده باشد، شماره خودِ پیوندشده به‌طور پیش‌فرض مجاز است
    • OpenClaw هرگز پیام‌های خصوصی خروجی fromMe را به‌طور خودکار جفت نمی‌کند (پیام‌هایی که از دستگاه پیوندشده برای خودتان می‌فرستید)

    سیاست گروه و فهرست‌های مجاز

    دسترسی گروه دو لایه دارد:

    1. فهرست مجاز عضویت گروه (channels.whatsapp.groups): اگر groups حذف شده باشد، همه گروه‌ها واجد شرایط‌اند؛ اگر وجود داشته باشد، به‌عنوان فهرست مجاز گروه عمل می‌کند ("*" همه را می‌پذیرد).
    2. سیاست فرستنده گروه (channels.whatsapp.groupPolicy + groupAllowFrom): open فهرست مجاز فرستندگان را دور می‌زند، allowlist به تطابق با groupAllowFrom (یا *) نیاز دارد، و disabled همه پیام‌های ورودی گروه را مسدود می‌کند.

    اگر groupAllowFrom تنظیم نشده باشد، بررسی‌های فرستنده در صورت داشتن ورودی به allowFrom بازمی‌گردند. فهرست‌های مجاز فرستندگان پیش از فعال‌سازی با اشاره/پاسخ ارزیابی می‌شوند.

    اگر هیچ بلوک channels.whatsappای وجود نداشته باشد، زمان اجرا به groupPolicy: "allowlist" بازمی‌گردد (همراه با ثبت هشدار)، حتی اگر channels.defaults.groupPolicy روی مقدار دیگری تنظیم شده باشد.

    اشاره‌ها و /activation

    پاسخ‌های گروه به‌طور پیش‌فرض به اشاره نیاز دارند. تشخیص اشاره شامل موارد زیر است:

    • اشاره‌های صریح WhatsApp به هویت ربات
    • الگوهای عبارت منظم اشاره پیکربندی‌شده (agents.list[].groupChat.mentionPatterns، با بازگشت به messages.groupChat.mentionPatterns)
    • رونوشت پیام‌های صوتی ورودی برای پیام‌های گروهی مجاز
    • تشخیص ضمنی پاسخ به ربات (فرستنده پاسخ با هویت ربات مطابقت دارد)

    امنیت: نقل‌قول/پاسخ فقط شرط اشاره را برآورده می‌کند — و به فرستنده مجوز نمی‌دهد. با groupPolicy: "allowlist"، فرستندگان خارج از فهرست مجاز حتی هنگام پاسخ به پیام یک کاربر مجاز نیز مسدود می‌مانند.

    فرمان فعال‌سازی در سطح نشست: /activation mention یا /activation always. این فرمان وضعیت نشست را به‌روزرسانی می‌کند (نه پیکربندی سراسری) و به مالک محدود است.

    پیوندهای ACP پیکربندی‌شده

    WhatsApp از پیوندهای پایدار ACP از طریق bindings[] سطح‌بالا پشتیبانی می‌کند:

    json5
    {  bindings: [    {      type: "acp",      agentId: "codex",      match: {        channel: "whatsapp",        accountId: "work",        peer: { kind: "direct", id: "+15555550123" },      },    },    {      type: "acp",      agentId: "codex",      match: {        channel: "whatsapp",        accountId: "work",        peer: { kind: "group", id: "120363424282127706@g.us" },      },    },  ],}

    گفت‌وگوهای مستقیم با شماره‌های E.164 مطابقت دارند؛ گروه‌ها با JIDهای گروه WhatsApp مطابقت دارند. فهرست‌های مجاز گروه، سیاست فرستنده و شرط اشاره/فعال‌سازی پیش از آن اجرا می‌شوند که OpenClaw از وجود نشست ACP پیوندخورده اطمینان حاصل کند. یک پیوند منطبق مالک مسیر است — گروه‌های پخش آن نوبت را به نشست‌های عادی WhatsApp منشعب نمی‌کنند.

    رفتار شماره شخصی و گفت‌وگو با خود

    وقتی شماره خودِ پیوندشده در allowFrom نیز وجود داشته باشد، حفاظت‌های گفت‌وگو با خود فعال می‌شوند: رسید خواندن برای نوبت‌های گفت‌وگو با خود ارسال نمی‌شود، رفتار فعال‌سازی خودکار mention-JID که به خودتان اعلان می‌دهد نادیده گرفته می‌شود و وقتی messages.responsePrefix تنظیم نشده باشد، پاسخ‌ها به‌طور پیش‌فرض به [{identity.name}] (یا [openclaw]) می‌روند.

    نرمال‌سازی پیام و زمینه

    پوش ورودی و زمینه پاسخ

    پیام‌های ورودی در پوش ورودی مشترک پیچیده می‌شوند. پاسخ نقل‌قول‌شده زمینه را به این شکل می‌افزاید:

    text
    [Replying to <sender> id:<stanzaId>]<quoted body or media placeholder>[/Replying]

    فراداده پاسخ (ReplyToId، ReplyToBody، ReplyToSender، و JID/E.164 فرستنده) در صورت دسترس‌بودن مقداردهی می‌شود. اگر مقصد نقل‌قول رسانه‌ای قابل‌بارگیری باشد، OpenClaw آن را از طریق ذخیره‌گاه عادی رسانه ورودی ذخیره می‌کند و MediaPath/MediaType را در دسترس قرار می‌دهد تا عامل بتواند به‌جای مشاهده صرفاً <media:image>، آن را مستقیماً بررسی کند.

    جای‌نگهدارهای رسانه و استخراج مکان/مخاطب

    پیام‌های صرفاً رسانه‌ای به جای‌نگهدارها نرمال می‌شوند: <media:image>، <media:video>، <media:audio>، <media:document>، <media:sticker>.

    وقتی بدنه فقط <media:audio> باشد، پیام‌های صوتی گروه مجاز پیش از شرط اشاره رونویسی می‌شوند؛ بنابراین گفتن اشاره ربات در پیام صوتی می‌تواند پاسخ را فعال کند. اگر رونوشت همچنان به ربات اشاره نکند، به‌جای جای‌نگهدار خام در تاریخچه در انتظار گروه باقی می‌ماند.

    بدنه‌های مکان به‌صورت متن مختصر مختصات نمایش داده می‌شوند. برچسب‌ها/نظرهای مکان و جزئیات مخاطب/vCard به‌صورت فراداده نامطمئن حصارکشی‌شده نمایش داده می‌شوند، نه متن درون‌خطی اعلان.

    تزریق تاریخچه در انتظار گروه

    پیام‌های پردازش‌نشده گروه در بافر می‌مانند و وقتی ربات سرانجام فعال شود، به‌عنوان زمینه تزریق می‌شوند.

    • محدودیت پیش‌فرض: 50
    • پیکربندی: channels.whatsapp.historyLimit، با بازگشت به messages.groupChat.historyLimit
    • 0 غیرفعال می‌کند

    نشانگرهای تزریق: [Chat messages since your last reply - for context] و [Current message - respond to this].

    رسیدهای خواندن

    برای پیام‌های ورودی پذیرفته‌شده به‌طور پیش‌فرض فعال است. غیرفعال‌سازی سراسری:

    json5
    { channels: { whatsapp: { sendReadReceipts: false } } }

    بازنویسی برای هر حساب: channels.whatsapp.accounts.<id>.sendReadReceipts. نوبت‌های گفت‌وگو با خود حتی در صورت فعال‌بودن سراسری، رسید خواندن را رد می‌کنند.

    تحویل، قطعه‌بندی و رسانه

    قطعه‌بندی متن
    • محدودیت پیش‌فرض قطعه: channels.whatsapp.textChunkLimit = 4000
    • channels.whatsapp.streaming.chunkMode = "length" | "newline"؛ newline مرزهای بند (خطوط خالی) را ترجیح می‌دهد و سپس به قطعه‌بندی ایمن از نظر طول بازمی‌گردد
    رفتار رسانه خروجی
    • از بارهای تصویر، ویدئو، صدا (پیام صوتی PTT) و سند پشتیبانی می‌کند
    • صدا به‌صورت بار audio متعلق به Baileys همراه با ptt: true ارسال می‌شود و به‌شکل پیام صوتی فشردن برای صحبت نمایش می‌یابد؛ audioAsVoice در بارهای پاسخ حفظ می‌شود تا خروجی پیام صوتی TTS صرف‌نظر از قالب مبدأ ارائه‌دهنده در همین مسیر باقی بماند
    • صدای بومی Ogg/Opus به‌صورت audio/ogg; codecs=opus ارسال می‌شود؛ هر چیز دیگری (از جمله خروجی MP3/WebM سرویس TTS در Microsoft Edge) پیش از تحویل PTT با ffmpeg به Ogg/Opus تک‌کاناله 48 kHz تبدیل می‌شود
    • /tts latest آخرین پاسخ دستیار را به‌صورت یک پیام صوتی ارسال می‌کند و ارسال‌های تکراری همان پاسخ را متوقف می‌کند؛ /tts chat on|off|default تبدیل خودکار متن به گفتار را برای گفت‌وگوی فعلی کنترل می‌کند
    • فعال‌کردن gifPlayback: true روی ویدئو امکان پخش GIF متحرک را فراهم می‌کند
    • forceDocument/asDocument تصاویر، GIFها و ویدئوهای خروجی را از طریق بار سند Baileys مسیریابی می‌کند تا از فشرده‌سازی رسانه WhatsApp جلوگیری شود و نام فایل و نوع MIME تفکیک‌شده حفظ شوند
    • شرح‌ها روی نخستین مورد رسانه‌ای در یک پاسخ چندرسانه‌ای اعمال می‌شوند، به‌جز پیام‌های صوتی PTT: صدا ابتدا بدون شرح ارسال می‌شود و سپس شرح به‌صورت یک پیام متنی جداگانه فرستاده می‌شود (کلاینت‌های WhatsApp شرح پیام صوتی را به‌طور یکسان نمایش نمی‌دهند)
    • منبع رسانه می‌تواند HTTP(S)، file:// یا یک مسیر محلی باشد
    محدودیت اندازه رسانه و رفتار جایگزین
    • سقف ذخیره ورودی و ارسال خروجی: channels.whatsapp.mediaMaxMb (پیش‌فرض 50)
    • بازنویسی برای هر حساب: channels.whatsapp.accounts.<id>.mediaMaxMb
    • تصاویر به‌طور خودکار برای انطباق با محدودیت‌ها بهینه می‌شوند (تغییر اندازه/پویش کیفیت)، مگر اینکه forceDocument/asDocument تحویل به‌صورت سند را درخواست کند
    • در صورت شکست ارسال رسانه، سازوکار جایگزین برای مورد نخست به‌جای حذف بی‌سروصدای پاسخ، یک هشدار متنی ارسال می‌کند

    نقل‌قول پاسخ

    channels.whatsapp.replyToMode نقل‌قول بومی پاسخ را کنترل می‌کند (پاسخ‌های خروجی به‌طور قابل‌مشاهده پیام ورودی را نقل‌قول می‌کنند):

    مقدار رفتار
    "off" (پیش‌فرض) هرگز نقل‌قول نکن؛ به‌صورت پیام ساده ارسال کن
    "first" فقط نخستین قطعه پاسخ خروجی را نقل‌قول کن
    "all" همه قطعه‌های پاسخ خروجی را نقل‌قول کن
    "batched" پاسخ‌های دسته‌ای صف‌شده را نقل‌قول کن؛ پاسخ‌های فوری را بدون نقل‌قول بگذار

    بازنویسی برای هر حساب: channels.whatsapp.accounts.<id>.replyToMode.

    json5
    { channels: { whatsapp: { replyToMode: "first" } } }

    سطح واکنش

    channels.whatsapp.reactionLevel گستره استفاده عامل از واکنش‌های ایموجی را کنترل می‌کند:

    سطح واکنش‌های تأیید واکنش‌های آغازشده توسط عامل
    "off" خیر خیر
    "ack" بله خیر
    "minimal" (پیش‌فرض) بله بله، با راهنمایی محافظه‌کارانه
    "extensive" بله بله، با راهنمایی تشویقی

    بازنویسی برای هر حساب: channels.whatsapp.accounts.<id>.reactionLevel.

    json5
    { channels: { whatsapp: { reactionLevel: "ack" } } }

    واکنش‌های تأیید دریافت

    channels.whatsapp.ackReaction هنگام دریافت پیام ورودی یک واکنش فوری می‌فرستد که با reactionLevel محدود می‌شود (هنگام "off" متوقف می‌شود):

    json5
    {  channels: {    whatsapp: {      ackReaction: {        emoji: "👀",        direct: true,        group: "mentions", // always | mentions | never      },    },  },}

    نکات: بلافاصله پس از پذیرش پیام ورودی (پیش از پاسخ) ارسال می‌شود؛ اگر ackReaction بدون emoji وجود داشته باشد، WhatsApp از ایموجی هویت عامل مسیریابی‌شده استفاده می‌کند و در صورت نبود آن به "👀" بازمی‌گردد (برای نداشتن تأیید، ackReaction را حذف کنید یا emoji: "" را تنظیم کنید)؛ شکست‌ها ثبت می‌شوند اما تحویل پاسخ را مسدود نمی‌کنند؛ حالت گروه mentions فقط در نوبت‌های فعال‌شده با اشاره واکنش نشان می‌دهد، درحالی‌که فعال‌سازی گروه always این بررسی را دور می‌زند؛ WhatsApp فقط از channels.whatsapp.ackReaction استفاده می‌کند (messages.ackReaction قدیمی در اینجا اعمال نمی‌شود).

    واکنش‌های وضعیت چرخه حیات

    messages.statusReactions.enabled: true را تنظیم کنید تا WhatsApp به‌جای باقی‌گذاشتن یک ایموجی ثابت دریافت، واکنش تأیید را در طول یک نوبت جایگزین کند و میان وضعیت‌هایی مانند در صف، در حال فکر، فعالیت ابزار، Compaction، انجام‌شده و خطا بچرخد:

    json5
    {  messages: {    statusReactions: {      enabled: true,      emojis: {        deploy: "🛫",        build: "🏗️",        concierge: "💁",      },    },  },}

    نکات: channels.whatsapp.ackReaction همچنان واجد شرایط بودن پیام‌های مستقیم و گروه‌ها را کنترل می‌کند؛ وضعیت در صف از همان ایموجی مؤثر واکنش‌های تأیید ساده استفاده می‌کند؛ WhatsApp برای هر پیام یک جایگاه واکنش ربات دارد، بنابراین به‌روزرسانی‌های چرخه حیات واکنش فعلی را در همان محل جایگزین می‌کنند؛ messages.removeAckAfterReply: true واکنش وضعیت نهایی را پس از مدت نگه‌داری پیکربندی‌شده برای انجام‌شده/خطا پاک می‌کند؛ دسته‌های ایموجی ابزار شامل tool، coding، web، deploy، build و concierge هستند.

    چندحسابی و اطلاعات اصالت‌سنجی

    انتخاب حساب و پیش‌فرض‌ها

    شناسه‌های حساب از channels.whatsapp.accounts می‌آیند. اگر default موجود باشد، همان حساب پیش‌فرض انتخاب می‌شود؛ در غیر این صورت، نخستین شناسه حساب پیکربندی‌شده (با مرتب‌سازی الفبایی) انتخاب می‌شود. شناسه‌های حساب برای جست‌وجوی داخلی نرمال‌سازی می‌شوند.

    مسیرهای اعتبارنامه و سازگاری با نسخه‌های قدیمی
    • مسیر احراز هویت فعلی: ~/.openclaw/credentials/whatsapp/<accountId>/creds.json (پشتیبان: creds.json.bak)
    • احراز هویت پیش‌فرض قدیمی در ~/.openclaw/credentials/ همچنان برای جریان‌های حساب پیش‌فرض شناسایی/مهاجرت می‌شود
    رفتار خروج

    openclaw channels logout --channel whatsapp [--account <id>] وضعیت احراز هویت WhatsApp را برای آن حساب پاک می‌کند. وقتی Gateway در دسترس باشد، خروج ابتدا شنونده فعال آن حساب را متوقف می‌کند تا نشست پیوندشده پیش از راه‌اندازی مجدد بعدی دیگر پیامی دریافت نکند. openclaw channels remove --channel whatsapp نیز پیش از غیرفعال‌کردن یا حذف پیکربندی حساب، شنونده فعال را متوقف می‌کند.

    در پوشه‌های احراز هویت قدیمی، oauth.json حفظ می‌شود، اما فایل‌های احراز هویت Baileys حذف می‌شوند.

    ابزارها، کنش‌ها و نوشتن پیکربندی

    • پشتیبانی ابزار عامل شامل کنش واکنش WhatsApp است (react).
    • دروازه‌های کنش: channels.whatsapp.actions.reactions، channels.whatsapp.actions.polls (کنش‌های موجود به‌طور پیش‌فرض true هستند)، channels.whatsapp.actions.calls (پیش‌فرض false، MeowCaller در بالا را ببینید).
    • نوشتن پیکربندی با آغازگری کانال به‌طور پیش‌فرض فعال است؛ با channels.whatsapp.configWrites: false غیرفعالش کنید.

    عیب‌یابی

    پیوند نشده است (QR لازم است)

    نشانه: وضعیت کانال پیوندنشده گزارش می‌شود.

    bash
    openclaw channels login --channel whatsappopenclaw channels status
    پیوندشده اما قطع است / چرخه اتصال مجدد

    نشانه: حساب پیوندشده با قطع‌های مکرر یا تلاش‌های مکرر برای اتصال مجدد.

    حساب‌های کم‌فعالیت می‌توانند پس از مهلت زمانی معمول پیام نیز متصل بمانند؛ نگهبان فقط زمانی راه‌اندازی مجدد می‌کند که فعالیت انتقال WhatsApp Web متوقف شود، سوکت بسته شود، یا فعالیت در سطح برنامه بیش از بازه ایمنی طولانی‌تر ساکت بماند (مدل زمان اجرا در بالا را ببینید).

    اگر گزارش‌ها status=408 Request Time-out Connection was lost را مکرراً نشان می‌دهند، زمان‌بندی‌های سوکت Baileys را در web.whatsapp تنظیم کنید. ابتدا keepAliveIntervalMs را به مقداری کمتر از مهلت بی‌کاری شبکه خود کاهش دهید و در پیوندهای کند یا با اتلاف داده، connectTimeoutMs را افزایش دهید:

    json5
    {  web: {    whatsapp: {      keepAliveIntervalMs: 15000,      connectTimeoutMs: 60000,      defaultQueryTimeoutMs: 60000,    },  },}

    راه‌حل:

    bash
    openclaw channels status --probeopenclaw doctoropenclaw logs --followopenclaw gateway status

    اگر پس از رفع مشکلات اتصال میزبان و زمان‌بندی، چرخه همچنان ادامه داشت، از پوشه احراز هویت حساب نسخه پشتیبان تهیه و دوباره پیوند برقرار کنید:

    bash
    cp -a ~/.openclaw/credentials/whatsapp/<accountId> \  ~/.openclaw/credentials/whatsapp/<accountId>.bakopenclaw channels logout --channel whatsapp --account <accountId>openclaw channels login --channel whatsapp --account <accountId>

    اگر ~/.openclaw/logs/whatsapp-health.log می‌گوید Gateway inactive اما openclaw gateway status و openclaw channels status --probe هر دو وضعیت سالم را نشان می‌دهند، openclaw doctor را اجرا کنید. در Linux، doctor درباره مدخل‌های قدیمی crontab که اسکریپت بازنشسته‌شده ~/.openclaw/bin/ensure-whatsapp.sh را فراخوانی می‌کنند هشدار می‌دهد؛ آن مدخل‌ها را با crontab -e حذف کنید — Cron ممکن است محیط گذرگاه کاربر systemd را نداشته باشد و باعث شود آن اسکریپت قدیمی سلامت Gateway را اشتباه گزارش کند.

    پایان مهلت ورود با QR پشت پراکسی

    نشانه: openclaw channels login --channel whatsapp پیش از نمایش یک QR قابل‌استفاده، با status=408 Request Time-out یا قطع اتصال سوکت TLS شکست می‌خورد.

    ورود WhatsApp Web از محیط استاندارد پراکسی میزبان Gateway استفاده می‌کند (HTTPS_PROXY، HTTP_PROXY، گونه‌های حروف کوچک و NO_PROXY). بررسی کنید فرایند Gateway متغیرهای محیطی پراکسی را به ارث می‌برد و NO_PROXY با mmg.whatsapp.net مطابقت ندارد.

    نبود شنونده فعال هنگام ارسال

    وقتی برای حساب مقصد هیچ شنونده فعال Gateway وجود نداشته باشد، ارسال‌های خروجی فوراً شکست می‌خورند. مطمئن شوید Gateway در حال اجرا و حساب پیوندشده است.

    پاسخ در رونوشت دیده می‌شود اما در WhatsApp نیست

    ردیف‌های رونوشت آنچه عامل تولید کرده است ثبت می‌کنند؛ تحویل WhatsApp جداگانه بررسی می‌شود. OpenClaw تنها پس از آن یک پاسخ خودکار را ارسال‌شده تلقی می‌کند که Baileys برای دست‌کم یک ارسال قابل‌مشاهده متن یا رسانه، شناسه پیام خروجی برگرداند.

    واکنش‌های تأیید، رسیدهای مستقل پیش از پاسخ هستند — موفقیت واکنش ثابت نمی‌کند پاسخ متنی/رسانه‌ای بعدی پذیرفته شده است. گزارش‌های Gateway را برای auto-reply delivery failed یا auto-reply was not accepted by WhatsApp provider بررسی کنید.

    نادیده‌گرفته‌شدن غیرمنتظره پیام‌های گروه

    به این ترتیب بررسی کنید: groupPolicy، groupAllowFrom/allowFrom، مدخل‌های فهرست مجاز groups، دروازه‌گذاری اشاره (requireMention + الگوهای اشاره) و کلیدهای تکراری در openclaw.json (مدخل‌های بعدی JSON5 مدخل‌های قبلی را بازنویسی می‌کنند — در هر دامنه فقط یک groupPolicy نگه دارید).

    اگر channels.whatsapp.groups وجود داشته باشد، WhatsApp همچنان می‌تواند پیام‌های گروه‌های دیگر را مشاهده کند، اما OpenClaw آن‌ها را پیش از مسیریابی نشست کنار می‌گذارد. JID گروه را به channels.whatsapp.groups اضافه کنید، یا برای پذیرش همه گروه‌ها، درحالی‌که مجوز فرستنده همچنان تحت کنترل groupPolicy/groupAllowFrom باقی می‌ماند، groups["*"] را اضافه کنید.

    هشدار زمان اجرای Bun

    Gatewayهای OpenClaw به Node نیاز دارند. Bun API مربوط به node:sqlite را که مخزن وضعیت متعارف استفاده می‌کند ارائه نمی‌دهد و doctor سرویس‌های قدیمی Bun را به Node مهاجرت می‌دهد.

    اعلان‌های سیستمی

    WhatsApp از اعلان‌های سیستمی به سبک Telegram برای گروه‌ها و گفت‌وگوهای مستقیم، از طریق نگاشت‌های groups و direct پشتیبانی می‌کند.

    تفکیک برای پیام‌های گروهی: ابتدا نگاشت مؤثر groups تعیین می‌شود — اگر حساب به هر شکلی کلید groups مخصوص خود را تعریف کند، آن کلید به‌طور کامل جایگزین نگاشت ریشه groups می‌شود (بدون ادغام عمیق). سپس جست‌وجوی اعلان روی همان نگاشت حاصل اجرا می‌شود:

    1. اعلان ویژه گروه (groups["<groupId>"].systemPrompt): وقتی مدخل گروه وجود داشته باشد و کلید systemPrompt آن تعریف شده باشد، استفاده می‌شود. رشته خالی ("") نویسه عام را نادیده می‌گیرد و هیچ اعلانی اعمال نمی‌کند.
    2. اعلان نویسه عام گروه (groups["*"].systemPrompt): وقتی مدخل گروه مشخص وجود نداشته باشد، یا بدون کلید systemPrompt وجود داشته باشد، استفاده می‌شود.

    تفکیک برای پیام‌های مستقیم از الگوی یکسانی در برابر نگاشت direct و direct["*"] پیروی می‌کند.

    تفاوت با Telegram: Telegram در یک راه‌اندازی چندحساب، groups ریشه را برای همه حساب‌ها نادیده می‌گیرد (حتی حساب‌هایی که groups مخصوص خود را ندارند) تا یک ربات پیام‌های گروه‌هایی را که عضو آن‌ها نیست دریافت نکند. WhatsApp این محافظ را اعمال نمی‌کند — groups/direct ریشه، صرف‌نظر از تعداد حساب‌ها، به هر حسابی که بازنویسی مخصوص خود را نداشته باشد به ارث می‌رسند. در راه‌اندازی چندحساب WhatsApp، اگر اعلان‌های مختص هر حساب می‌خواهید، نگاشت کامل را صریحاً زیر هر حساب تعریف کنید.

    رفتار مهم:

    • channels.whatsapp.groups هم نگاشت پیکربندی هر گروه و هم فهرست مجاز گروه در سطح گفت‌وگو است. در دامنه ریشه یا حساب، groups["*"] به‌معنای «همه گروه‌ها پذیرفته می‌شوند» برای آن دامنه است.
    • فقط زمانی نویسه عام systemPrompt را اضافه کنید که از قبل می‌خواهید آن دامنه همه گروه‌ها را بپذیرد. برای واجد شرایط نگه‌داشتن فقط مجموعه ثابتی از شناسه‌های گروه، به‌جای استفاده از groups["*"]، اعلان را در هر مدخل صریحاً مجازشده تکرار کنید.
    • پذیرش گروه و مجوز فرستنده دو بررسی جداگانه‌اند. groups["*"] دامنه گروه‌هایی را که به پردازش گروه می‌رسند گسترش می‌دهد؛ این گزینه همه فرستندگان آن گروه‌ها را مجاز نمی‌کند — کنترل آن همچنان بر عهده groupPolicy/groupAllowFrom است.
    • channels.whatsapp.direct برای پیام‌های مستقیم هیچ اثر جانبی معادلی ندارد: direct["*"] فقط پس از آنکه یک پیام مستقیم از طریق dmPolicy به‌همراه allowFrom یا قواعد مخزن جفت‌سازی پذیرفته شد، پیکربندی پیش‌فرض ارائه می‌کند.

    مثال:

    json5
    {  channels: {    whatsapp: {      groups: {        // فقط در صورتی استفاده کنید که همه گروه‌ها باید در دامنه ریشه پذیرفته شوند.        // برای همه حساب‌هایی اعمال می‌شود که نگاشت groups مخصوص خود را تعریف نکرده‌اند.        "*": { systemPrompt: "اعلان پیش‌فرض برای همه گروه‌ها." },      },      direct: {        // برای همه حساب‌هایی اعمال می‌شود که نگاشت direct مخصوص خود را تعریف نکرده‌اند.        "*": { systemPrompt: "اعلان پیش‌فرض برای همه گفت‌وگوهای مستقیم." },      },      accounts: {        work: {          groups: {            // این حساب groups مخصوص خود را تعریف می‌کند، بنابراین groups ریشه به‌طور کامل            // جایگزین می‌شود. برای حفظ نویسه عام، "*" را اینجا نیز صریحاً تعریف کنید.            "120363406415684625@g.us": {              requireMention: false,              systemPrompt: "بر مدیریت پروژه تمرکز کن.",            },            // فقط در صورتی استفاده کنید که همه گروه‌ها باید در این حساب پذیرفته شوند.            "*": { systemPrompt: "اعلان پیش‌فرض برای گروه‌های کاری." },          },          direct: {            // این حساب نگاشت direct مخصوص خود را تعریف می‌کند، بنابراین مدخل‌های direct ریشه            // کاملاً جایگزین می‌شوند. برای حفظ نویسه عام، "*" را اینجا نیز صریحاً تعریف کنید.            "+15551234567": { systemPrompt: "اعلان برای یک گفت‌وگوی مستقیم کاری مشخص." },            "*": { systemPrompt: "اعلان پیش‌فرض برای گفت‌وگوهای مستقیم کاری." },          },        },      },    },  },}

    اشاره‌گرهای مرجع پیکربندی

    مرجع اصلی: مرجع پیکربندی - WhatsApp

    حوزه فیلدها
    دسترسی dmPolicy، allowFrom، groupPolicy، groupAllowFrom، groups
    تحویل textChunkLimit، streaming.chunkMode، mediaMaxMb، sendReadReceipts، ackReaction، reactionLevel
    چندحساب accounts.<id>.enabled، accounts.<id>.authDir و دیگر بازنویسی‌های مختص هر حساب
    عملیات configWrites، debounceMs، web.enabled، web.heartbeatSeconds، web.reconnect.*، web.whatsapp.*
    رفتار نشست session.dmScope، historyLimit، dmHistoryLimit، dms.<id>.historyLimit
    اعلان‌ها groups.<id>.systemPrompt، groups["*"].systemPrompt، direct.<id>.systemPrompt، direct["*"].systemPrompt

    مرتبط

    Was this useful?
    On this page

    On this page