Mainstream messaging
Signal
وضعیت: یکپارچهسازی خارجی CLI. Gateway از طریق HTTP با signal-cli ارتباط برقرار میکند؛ یا daemon بومی (JSON-RPC + SSE) یا کانتینر bbernhard/signal-cli-rest-api (REST + WebSocket).
پیشنیازها
- OpenClaw روی سرور شما نصب شده باشد (روند Linux زیر روی Ubuntu 24 آزمایش شده است).
- یکی از اینها:
signal-cliروی میزبان در دسترس باشد (حالت بومی)، یا- کانتینر Docker مربوط به
bbernhard/signal-cli-rest-api(حالت کانتینر).
- یک شماره تلفن که بتواند یک پیامک تأیید دریافت کند (برای مسیر ثبتنام با پیامک).
- دسترسی مرورگر برای کپچای Signal (
signalcaptchas.org) هنگام ثبتنام.
راهاندازی سریع (مبتدی)
- برای ربات از یک شماره Signal جداگانه استفاده کنید (توصیه میشود).
signal-cliرا نصب کنید (اگر از ساخت JVM استفاده میکنید، Java لازم است).- یکی از مسیرهای راهاندازی را انتخاب کنید:
- مسیر A (پیوند QR):
signal-cli link -n "OpenClaw"و اسکن با Signal. - مسیر B (ثبتنام پیامکی): یک شماره اختصاصی را با کپچا + تأیید پیامکی ثبت کنید.
- مسیر A (پیوند QR):
- OpenClaw را پیکربندی کنید و Gateway را راهاندازی مجدد کنید.
- یک پیام مستقیم اولیه بفرستید و جفتسازی را تأیید کنید (
openclaw pairing approve signal <CODE>).
پیکربندی حداقلی:
{ channels: { signal: { enabled: true, account: "+15551234567", cliPath: "signal-cli", dmPolicy: "pairing", allowFrom: ["+15557654321"], }, },}مرجع فیلدها:
| فیلد | توضیح |
|---|---|
account |
شماره تلفن ربات در قالب E.164 (+15551234567) |
cliPath |
مسیر signal-cli (signal-cli اگر در PATH باشد) |
dmPolicy |
سیاست دسترسی پیام مستقیم (pairing توصیه میشود) |
allowFrom |
شمارههای تلفن یا مقدارهای uuid:<id> که اجازه پیام مستقیم دارند |
چیستی آن
- کانال Signal از طریق
signal-cli(نه libsignal تعبیهشده). - مسیریابی قطعی: پاسخها همیشه به Signal برمیگردند.
- پیامهای مستقیم نشست اصلی عامل را به اشتراک میگذارند؛ گروهها جدا هستند (
agent:<agentId>:signal:group:<groupId>).
نوشتن پیکربندی
بهطور پیشفرض، Signal اجازه دارد بهروزرسانیهای پیکربندی فعالشده با /config set|unset را بنویسد (به commands.config: true نیاز دارد).
غیرفعالسازی با:
{ channels: { signal: { configWrites: false } },}مدل شماره (مهم)
- Gateway به یک دستگاه Signal متصل میشود (حساب
signal-cli). - اگر ربات را روی حساب شخصی Signal خودتان اجرا کنید، پیامهای خودتان را نادیده میگیرد (محافظت در برابر حلقه).
- برای «من به ربات پیام میدهم و پاسخ میدهد»، از یک شماره ربات جداگانه استفاده کنید.
مسیر راهاندازی A: پیوند دادن حساب Signal موجود (QR)
signal-cliرا نصب کنید (ساخت JVM یا بومی).- یک حساب ربات را پیوند دهید:
signal-cli link -n "OpenClaw"سپس QR را در Signal اسکن کنید.
- Signal را پیکربندی کنید و Gateway را شروع کنید.
نمونه:
{ channels: { signal: { enabled: true, account: "+15551234567", cliPath: "signal-cli", dmPolicy: "pairing", allowFrom: ["+15557654321"], }, },}پشتیبانی چندحسابی: از channels.signal.accounts با پیکربندی جداگانه برای هر حساب و name اختیاری استفاده کنید. برای الگوی مشترک، gateway/configuration را ببینید.
مسیر راهاندازی B: ثبت شماره اختصاصی ربات (پیامک، Linux)
وقتی بهجای پیوند دادن یک حساب برنامه Signal موجود، یک شماره اختصاصی ربات میخواهید، از این روش استفاده کنید.
- شمارهای تهیه کنید که بتواند پیامک دریافت کند (یا تأیید صوتی برای خطوط ثابت).
- برای جلوگیری از تداخل حساب/نشست، از شماره اختصاصی ربات استفاده کنید.
signal-cliرا روی میزبان Gateway نصب کنید:
VERSION=$(curl -Ls -o /dev/null -w %{url_effective} https://github.com/AsamK/signal-cli/releases/latest | sed -e 's/^.*\/v//')curl -L -O "https://github.com/AsamK/signal-cli/releases/download/v${VERSION}/signal-cli-${VERSION}-Linux-native.tar.gz"sudo tar xf "signal-cli-${VERSION}-Linux-native.tar.gz" -C /optsudo ln -sf /opt/signal-cli /usr/local/bin/signal-cli --versionاگر از ساخت JVM (signal-cli-${VERSION}.tar.gz) استفاده میکنید، ابتدا JRE 25+ را نصب کنید.
signal-cli را بهروز نگه دارید؛ بالادست اشاره میکند که نسخههای قدیمی با تغییر APIهای سرور Signal ممکن است از کار بیفتند.
- شماره را ثبت و تأیید کنید:
signal-cli -a +<BOT_PHONE_NUMBER> registerاگر کپچا لازم بود:
https://signalcaptchas.org/registration/generate.htmlرا باز کنید.- کپچا را تکمیل کنید، مقصد پیوند
signalcaptcha://...را از "Open Signal" کپی کنید. - در صورت امکان، از همان IP خارجی نشست مرورگر اجرا کنید.
- ثبتنام را فوراً دوباره اجرا کنید (توکنهای کپچا سریع منقضی میشوند):
signal-cli -a +<BOT_PHONE_NUMBER> register --captcha '<SIGNALCAPTCHA_URL>'signal-cli -a +<BOT_PHONE_NUMBER> verify <VERIFICATION_CODE>- OpenClaw را پیکربندی کنید، Gateway را راهاندازی مجدد کنید، کانال را بررسی کنید:
# If you run the gateway as a user systemd service:systemctl --user restart openclaw-gateway.service # Then verify:openclaw doctoropenclaw channels status --probe- فرستنده پیام مستقیم خود را جفت کنید:
- هر پیامی را به شماره ربات بفرستید.
- کد را روی سرور تأیید کنید:
openclaw pairing approve signal <PAIRING_CODE>. - برای جلوگیری از "Unknown contact"، شماره ربات را بهعنوان مخاطب در تلفن خود ذخیره کنید.
ارجاعهای بالادست:
- README مربوط به
signal-cli:https://github.com/AsamK/signal-cli - روند کپچا:
https://github.com/AsamK/signal-cli/wiki/Registration-with-captcha - روند پیونددهی:
https://github.com/AsamK/signal-cli/wiki/Linking-other-devices-(Provisioning)
حالت daemon خارجی (httpUrl)
اگر میخواهید خودتان signal-cli را مدیریت کنید (شروع سرد کند JVM، مقداردهی اولیه کانتینر، یا CPUهای مشترک)، daemon را جداگانه اجرا کنید و OpenClaw را به آن اشاره دهید:
{ channels: { signal: { httpUrl: "http://127.0.0.1:8080", autoStart: false, }, },}این کار راهاندازی خودکار و انتظار شروع داخل OpenClaw را رد میکند. برای شروعهای کند هنگام راهاندازی خودکار، channels.signal.startupTimeoutMs را تنظیم کنید.
حالت کانتینر (bbernhard/signal-cli-rest-api)
بهجای اجرای بومی signal-cli، میتوانید از کانتینر Docker مربوط به bbernhard/signal-cli-rest-api استفاده کنید. این، signal-cli را پشت یک REST API و رابط WebSocket قرار میدهد.
نیازمندیها:
- کانتینر باید با
MODE=json-rpcاجرا شود تا دریافت پیام بیدرنگ انجام شود. - قبل از اتصال OpenClaw، حساب Signal خود را داخل کانتینر ثبت یا پیوند کنید.
نمونه سرویس docker-compose.yml:
signal-cli: image: bbernhard/signal-cli-rest-api:latest environment: MODE: json-rpc ports: - "8080:8080" volumes: - signal-cli-data:/home/.local/share/signal-cliپیکربندی OpenClaw:
{ channels: { signal: { enabled: true, account: "+15551234567", httpUrl: "http://signal-cli:8080", autoStart: false, apiMode: "container", // or "auto" to detect automatically }, },}فیلد apiMode کنترل میکند OpenClaw از کدام پروتکل استفاده کند:
| مقدار | رفتار |
|---|---|
"auto" |
(پیشفرض) هر دو انتقال را بررسی میکند؛ پخش جریانی دریافت WebSocket کانتینر را اعتبارسنجی میکند |
"native" |
اجبار به signal-cli بومی (JSON-RPC در /api/v1/rpc، SSE در /api/v1/events) |
"container" |
اجبار به کانتینر bbernhard (REST در /v2/send، WebSocket در /v1/receive/{account}) |
وقتی apiMode برابر "auto" باشد، OpenClaw حالت شناساییشده را برای ۳۰ ثانیه cache میکند تا از بررسیهای تکراری جلوگیری شود. دریافت کانتینری فقط پس از ارتقای /v1/receive/{account} به WebSocket برای پخش جریانی انتخاب میشود، که به MODE=json-rpc نیاز دارد.
حالت کانتینر همان عملیات کانال Signal را در جاهایی که کانتینر APIهای متناظر را ارائه میکند مانند حالت بومی پشتیبانی میکند: ارسالها، دریافتها، پیوستها، نشانگرهای تایپ، رسیدهای خواندن/دیدهشدن، واکنشها، گروهها و متن سبکدهیشده. OpenClaw فراخوانیهای RPC بومی Signal خود را به payloadهای REST کانتینر ترجمه میکند، از جمله شناسههای گروه group.{base64(internal_id)} و text_mode: "styled" برای متن قالببندیشده.
نکات عملیاتی:
- با حالت کانتینر از
autoStart: falseاستفاده کنید. وقتیapiMode: "container"انتخاب شده است، OpenClaw نباید daemon بومی را اجرا کند. - برای دریافت از
MODE=json-rpcاستفاده کنید.MODE=normalمیتواند باعث شود/v1/aboutسالم به نظر برسد، اما/v1/receive/{account}به WebSocket ارتقا پیدا نمیکند، بنابراین OpenClaw در حالتautoپخش جریانی دریافت کانتینر را انتخاب نمیکند. - وقتی میدانید
httpUrlبه REST API متعلق به bbernhard اشاره میکند،apiMode: "container"را تنظیم کنید. وقتی میدانید به JSON-RPC/SSE بومیsignal-cliاشاره میکند،apiMode: "native"را تنظیم کنید. وقتی استقرار ممکن است متفاوت باشد، از"auto"استفاده کنید. - دانلودهای پیوست کانتینر همان محدودیتهای بایت رسانه را مانند حالت بومی رعایت میکنند. پاسخهای بیش از حد بزرگ، وقتی سرور
Content-Lengthمیفرستد پیش از buffer کامل رد میشوند، و در غیر این صورت هنگام streaming رد میشوند.
کنترل دسترسی (پیامهای مستقیم + گروهها)
پیامهای مستقیم:
- پیشفرض:
channels.signal.dmPolicy = "pairing". - فرستندههای ناشناخته یک کد جفتسازی دریافت میکنند؛ پیامها تا زمان تأیید نادیده گرفته میشوند (کدها پس از ۱ ساعت منقضی میشوند).
- تأیید از طریق:
openclaw pairing list signalopenclaw pairing approve signal <CODE>
- جفتسازی تبادل توکن پیشفرض برای پیامهای مستقیم Signal است. جزئیات: جفتسازی
- فرستندههای فقط UUID (از
sourceUuid) بهصورتuuid:<id>درchannels.signal.allowFromذخیره میشوند.
گروهها:
channels.signal.groupPolicy = open | allowlist | disabled.channels.signal.groupAllowFromکنترل میکند وقتیallowlistتنظیم شده است، کدام گروهها یا فرستندهها میتوانند پاسخهای گروهی را فعال کنند؛ ورودیها میتوانند شناسههای گروه Signal (خام،group:<id>، یاsignal:group:<id>)، شمارههای تلفن فرستنده، مقدارهایuuid:<id>، یا*باشند.channels.signal.groups["<group-id>" | "*"]میتواند رفتار گروه را باrequireMention،toolsوtoolsBySenderoverride کند.- برای overrideهای جداگانه هر حساب در راهاندازیهای چندحسابی، از
channels.signal.accounts.<id>.groupsاستفاده کنید. - allowlist کردن یک گروه Signal از طریق
groupAllowFromبهخودیخود دروازهگذاری mention را غیرفعال نمیکند. یک ورودی مشخصاً پیکربندیشدهchannels.signal.groups["<group-id>"]همه پیامهای گروه را پردازش میکند، مگر اینکهrequireMention=trueتنظیم شده باشد. - نکته زمان اجرا: اگر
channels.signalکاملاً وجود نداشته باشد، runtime برای بررسیهای گروه بهgroupPolicy="allowlist"برمیگردد (حتی اگرchannels.defaults.groupPolicyتنظیم شده باشد).
نحوه کار (رفتار)
- حالت بومی:
signal-cliبهعنوان daemon اجرا میشود؛ Gateway رویدادها را از طریق SSE میخواند. - حالت کانتینر: Gateway از طریق REST API ارسال میکند و از طریق WebSocket دریافت میکند.
- پیامهای ورودی به envelope مشترک کانال نرمالسازی میشوند.
- پاسخها همیشه به همان شماره یا گروه برمیگردند.
رسانه + محدودیتها
- متن خروجی به
channels.signal.textChunkLimitقطعهبندی میشود (پیشفرض ۴۰۰۰). - قطعهبندی اختیاری بر اساس خط جدید:
channels.signal.chunkMode="newline"را تنظیم کنید تا پیش از قطعهبندی بر اساس طول، متن بر اساس خطوط خالی (مرزهای پاراگراف) تقسیم شود. - پیوستها پشتیبانی میشوند (base64 از
signal-cliدریافت میشود). - پیوستهای یادداشت صوتی وقتی
contentTypeوجود ندارد، از نام فایلsignal-cliبهعنوان fallback نوع MIME استفاده میکنند، بنابراین رونویسی صوتی همچنان میتواند یادداشتهای صوتی AAC را طبقهبندی کند. - سقف پیشفرض رسانه:
channels.signal.mediaMaxMb(پیشفرض ۸). - برای رد کردن دانلود رسانه از
channels.signal.ignoreAttachmentsاستفاده کنید. - زمینه تاریخچه گروه از
channels.signal.historyLimit(یاchannels.signal.accounts.*.historyLimit) استفاده میکند و بهmessages.groupChat.historyLimitبرمیگردد. برای غیرفعالسازی،0را تنظیم کنید (پیشفرض ۵۰).
تایپ + رسیدهای خواندن
- نشانگرهای تایپ: OpenClaw سیگنالهای تایپ را از طریق
signal-cli sendTypingمیفرستد و هنگام اجرای پاسخ آنها را تازهسازی میکند. - رسیدهای خواندن: وقتی
channels.signal.sendReadReceiptsبرابر true باشد، OpenClaw رسیدهای خواندن را برای پیامهای مستقیم مجاز forward میکند. - Signal-cli رسیدهای خواندن برای گروهها را ارائه نمیکند.
واکنشها (ابزار پیام)
- از
message action=reactهمراه باchannel=signalاستفاده کنید. - اهداف: فرستنده بهصورت E.164 یا UUID (از
uuid:<id>در خروجی جفتسازی استفاده کنید؛ UUID تنها هم کار میکند). messageIdهمان برچسب زمانی Signal برای پیامی است که به آن واکنش میدهید.- واکنشهای گروهی به
targetAuthorیاtargetAuthorUuidنیاز دارند.
نمونهها:
message action=react channel=signal target=uuid:123e4567-e89b-12d3-a456-426614174000 messageId=1737630212345 emoji=🔥message action=react channel=signal target=+15551234567 messageId=1737630212345 emoji=🔥 remove=truemessage action=react channel=signal target=signal:group:<groupId> targetAuthor=uuid:<sender-uuid> messageId=1737630212345 emoji=✅پیکربندی:
channels.signal.actions.reactions: فعال/غیرفعال کردن کنشهای واکنش (پیشفرض true).channels.signal.reactionLevel:off | ack | minimal | extensive.off/ackواکنشهای عامل را غیرفعال میکند (ابزار پیامreactخطا میدهد).minimal/extensiveواکنشهای عامل را فعال میکند و سطح راهنما را تنظیم میکند.
- بازنویسیهای مخصوص هر حساب:
channels.signal.accounts.<id>.actions.reactions،channels.signal.accounts.<id>.reactionLevel.
اهداف تحویل (CLI/cron)
- پیامهای مستقیم:
signal:+15551234567(یا E.164 ساده). - پیامهای مستقیم UUID:
uuid:<id>(یا UUID تنها). - گروهها:
signal:group:<groupId>. - نامهای کاربری:
username:<name>(اگر توسط حساب Signal شما پشتیبانی شود).
عیبیابی
ابتدا این نردبان را اجرا کنید:
openclaw statusopenclaw gateway statusopenclaw logs --followopenclaw doctoropenclaw channels status --probeسپس در صورت نیاز وضعیت جفتسازی پیام مستقیم را تأیید کنید:
openclaw pairing list signalخرابیهای رایج:
- Daemon در دسترس است اما پاسخی نمیآید: تنظیمات حساب/daemon (
httpUrl،account) و حالت دریافت را بررسی کنید. - پیامهای مستقیم نادیده گرفته میشوند: فرستنده در انتظار تأیید جفتسازی است.
- پیامهای گروهی نادیده گرفته میشوند: گیتینگ فرستنده/اشاره در گروه تحویل را مسدود میکند.
- خطاهای اعتبارسنجی پیکربندی پس از ویرایشها:
openclaw doctor --fixرا اجرا کنید. - Signal در تشخیصها وجود ندارد:
channels.signal.enabled: trueرا تأیید کنید.
بررسیهای اضافه:
openclaw pairing list signalpgrep -af signal-cligrep -i "signal" "/tmp/openclaw/openclaw-$(date +%Y-%m-%d).log" | tail -20برای جریان تریاژ: /channels/troubleshooting.
نکات امنیتی
signal-cliکلیدهای حساب را بهصورت محلی ذخیره میکند (معمولاً در~/.local/share/signal-cli/data/).- پیش از مهاجرت یا بازسازی سرور، از وضعیت حساب Signal پشتیبان بگیرید.
channels.signal.dmPolicy: "pairing"را نگه دارید، مگر اینکه صراحتاً دسترسی گستردهتر به پیام مستقیم میخواهید.- تأیید SMS فقط برای جریانهای ثبتنام یا بازیابی لازم است، اما از دست دادن کنترل شماره/حساب میتواند ثبتنام دوباره را پیچیده کند.
مرجع پیکربندی (Signal)
پیکربندی کامل: پیکربندی
گزینههای ارائهدهنده:
channels.signal.enabled: فعال/غیرفعال کردن راهاندازی کانال.channels.signal.apiMode:auto | native | container(پیشفرض: auto). حالت کانتینر را ببینید.channels.signal.account: E.164 برای حساب ربات.channels.signal.cliPath: مسیرsignal-cli.channels.signal.httpUrl: URL کامل daemon (host/port را بازنویسی میکند).channels.signal.httpHost،channels.signal.httpPort: اتصال daemon (پیشفرض 127.0.0.1:8080).channels.signal.autoStart: اجرای خودکار daemon (اگرhttpUrlتنظیم نشده باشد، پیشفرض true).channels.signal.startupTimeoutMs: زمان انتظار راهاندازی برحسب ms (سقف 120000).channels.signal.receiveMode:on-start | manual.channels.signal.ignoreAttachments: رد کردن دانلود پیوستها.channels.signal.ignoreStories: نادیده گرفتن استوریها از daemon.channels.signal.sendReadReceipts: بازفرستادن رسیدهای خواندهشدن.channels.signal.dmPolicy:pairing | allowlist | open | disabled(پیشفرض: pairing).channels.signal.allowFrom: فهرست مجاز پیام مستقیم (E.164 یاuuid:<id>).openبه"*"نیاز دارد. Signal نام کاربری ندارد؛ از شناسههای تلفن/UUID استفاده کنید.channels.signal.groupPolicy:open | allowlist | disabled(پیشفرض: allowlist).channels.signal.groupAllowFrom: فهرست مجاز گروه؛ شناسههای گروه Signal (خام،group:<id>، یاsignal:group:<id>)، شمارههای E.164 فرستنده، یا مقادیرuuid:<id>را میپذیرد.channels.signal.groups: بازنویسیهای مخصوص هر گروه که با شناسه گروه Signal (یا"*") کلیدگذاری شدهاند. فیلدهای پشتیبانیشده:requireMention،tools،toolsBySender.channels.signal.accounts.<id>.groups: نسخه مخصوص هر حساب ازchannels.signal.groupsبرای تنظیمات چندحسابی.channels.signal.historyLimit: بیشینه پیامهای گروهی برای افزودن بهعنوان زمینه (0 غیرفعال میکند).channels.signal.dmHistoryLimit: حد تاریخچه پیام مستقیم برحسب نوبتهای کاربر. بازنویسیهای مخصوص هر کاربر:channels.signal.dms["<phone_or_uuid>"].historyLimit.channels.signal.textChunkLimit: اندازه قطعه خروجی (نویسه).channels.signal.chunkMode:length(پیشفرض) یاnewlineبرای تقسیم بر اساس خطوط خالی (مرزهای پاراگراف) پیش از قطعهبندی بر اساس طول.channels.signal.mediaMaxMb: سقف رسانه ورودی/خروجی (MB).
گزینههای سراسری مرتبط:
agents.list[].groupChat.mentionPatterns(Signal از اشارههای بومی پشتیبانی نمیکند).messages.groupChat.mentionPatterns(جایگزین سراسری).messages.responsePrefix.
مرتبط
- نمای کلی کانالها — همه کانالهای پشتیبانیشده
- جفتسازی — احراز هویت پیام مستقیم و جریان جفتسازی
- گروهها — رفتار گفتوگوی گروهی و گیتینگ اشاره
- مسیریابی کانال — مسیریابی نشست برای پیامها
- امنیت — مدل دسترسی و سختسازی