Messages and delivery

جریان‌سازی و قطعه‌بندی

OpenClaw دو لایهٔ استریم جداگانه دارد:

  • استریم بلوکی (کانال‌ها): هم‌زمان با نوشتن دستیار، بلوک‌های کامل‌شده را منتشر می‌کند. این‌ها پیام‌های عادی کانال هستند (نه دلتاهای توکن).
  • استریم پیش‌نمایش (Telegram/Discord/Slack): هنگام تولید، یک پیام پیش‌نمایش موقت را به‌روزرسانی می‌کند.

امروز استریم واقعی دلتاهای توکن به پیام‌های کانال وجود ندارد. استریم پیش‌نمایش مبتنی بر پیام است (ارسال + ویرایش/افزودن).

استریم بلوکی (پیام‌های کانال)

استریم بلوکی خروجی دستیار را هنگام آماده‌شدن، در قطعه‌های درشت ارسال می‌کند.

Model output
  └─ text_delta/events
       ├─ (blockStreamingBreak=text_end)
       │    └─ chunker emits blocks as buffer grows
       └─ (blockStreamingBreak=message_end)
            └─ chunker flushes at message_end
                   └─ channel send (block replies)

راهنما:

  • text_delta/events: رویدادهای استریم مدل (ممکن است برای مدل‌های غیر استریمی کم‌تعداد باشند).
  • chunker: EmbeddedBlockChunker که کران‌های کمینه/بیشینه + ترجیح شکست را اعمال می‌کند.
  • channel send: پیام‌های خروجی واقعی (پاسخ‌های بلوکی).

کنترل‌ها:

  • agents.defaults.blockStreamingDefault: "on"/"off" (پیش‌فرض خاموش).
  • بازنویسی‌های کانال: *.blockStreaming (و گونه‌های هر حساب) برای اجبار "on"/"off" برای هر کانال.
  • agents.defaults.blockStreamingBreak: "text_end" یا "message_end".
  • agents.defaults.blockStreamingChunk: { minChars, maxChars, breakPreference? }.
  • agents.defaults.blockStreamingCoalesce: { minChars?, maxChars?, idleMs? } (ادغام بلوک‌های استریم‌شده پیش از ارسال).
  • سقف سخت کانال: *.textChunkLimit (برای نمونه، channels.whatsapp.textChunkLimit).
  • حالت قطعه‌کردن کانال: *.chunkMode (پیش‌فرض length، مقدار newline پیش از قطعه‌کردن بر اساس طول، بر اساس خط‌های خالی (مرزهای بند) جدا می‌کند).
  • سقف نرم Discord: channels.discord.maxLinesPerMessage (پیش‌فرض 17) پاسخ‌های بلند را جدا می‌کند تا از بریده‌شدن UI جلوگیری شود.

معنای مرزها:

  • text_end: به‌محض اینکه قطعه‌کن بلوک تولید کند، بلوک‌ها را استریم می‌کند؛ در هر text_end تخلیه می‌کند.
  • message_end: تا پایان پیام دستیار صبر می‌کند، سپس خروجی بافرشده را تخلیه می‌کند.

message_end همچنان اگر متن بافرشده از maxChars بیشتر باشد از قطعه‌کن استفاده می‌کند، بنابراین می‌تواند در پایان چندین قطعه منتشر کند.

تحویل رسانه با استریم بلوکی

دستورهای MEDIA: فرادادهٔ عادی تحویل هستند. وقتی استریم بلوکی یک بلوک رسانه‌ای را زودتر ارسال کند، OpenClaw آن تحویل را برای نوبت به خاطر می‌سپارد. اگر بار نهایی دستیار همان نشانی رسانه را تکرار کند، تحویل نهایی به‌جای ارسال دوبارهٔ پیوست، رسانهٔ تکراری را حذف می‌کند.

بارهای نهایی کاملاً تکراری سرکوب می‌شوند. اگر بار نهایی متن متمایزی پیرامون رسانه‌ای اضافه کند که قبلاً استریم شده است، OpenClaw همچنان متن جدید را می‌فرستد و رسانه را تک‌تحویلی نگه می‌دارد. این کار از تکرار یادداشت‌های صوتی یا فایل‌ها در کانال‌هایی مانند Telegram جلوگیری می‌کند، وقتی یک عامل هنگام استریم MEDIA: منتشر می‌کند و ارائه‌دهنده نیز آن را در پاسخ کامل‌شده می‌گنجاند.

الگوریتم قطعه‌کردن (کران‌های پایین/بالا)

قطعه‌کردن بلوک با EmbeddedBlockChunker پیاده‌سازی شده است:

  • کران پایین: تا زمانی که بافر >= minChars نشود منتشر نکن (مگر اینکه اجباری باشد).
  • کران بالا: شکست‌ها را پیش از maxChars ترجیح بده؛ اگر اجباری بود، در maxChars جدا کن.
  • ترجیح شکست: paragraphnewlinesentencewhitespace → شکست سخت.
  • حصارهای کد: هرگز داخل حصارها جدا نکن؛ وقتی در maxChars اجباری جدا می‌کنی، حصار را ببند + دوباره باز کن تا Markdown معتبر بماند.

maxChars به textChunkLimit کانال محدود می‌شود، بنابراین نمی‌توانید از سقف‌های هر کانال فراتر بروید.

هم‌تجمیعی (ادغام بلوک‌های استریم‌شده)

وقتی استریم بلوکی فعال باشد، OpenClaw می‌تواند قطعه‌های بلوکی پیاپی را پیش از ارسال ادغام کند. این کار «هرزپیام تک‌خطی» را کاهش می‌دهد و همچنان خروجی تدریجی فراهم می‌کند.

  • هم‌تجمیعی پیش از تخلیه، منتظر فاصله‌های بیکاری (idleMs) می‌ماند.
  • بافرها با maxChars محدود می‌شوند و اگر از آن فراتر بروند تخلیه می‌شوند.
  • minChars از ارسال قطعه‌های بسیار کوچک جلوگیری می‌کند تا متن کافی جمع شود (تخلیهٔ نهایی همیشه متن باقی‌مانده را ارسال می‌کند).
  • پیونددهنده از blockStreamingChunk.breakPreference مشتق می‌شود (paragraph\n\n، newline\n، sentence → فاصله).
  • بازنویسی‌های کانال از طریق *.blockStreamingCoalesce در دسترس هستند (شامل پیکربندی‌های هر حساب).
  • مقدار پیش‌فرض minChars برای هم‌تجمیعی، برای Signal/Slack/Discord به 1500 افزایش داده می‌شود مگر اینکه بازنویسی شده باشد.

آهنگ انسانی بین بلوک‌ها

وقتی استریم بلوکی فعال باشد، می‌توانید بین پاسخ‌های بلوکی (پس از بلوک اول) یک مکث تصادفی‌شده اضافه کنید. این کار پاسخ‌های چندحبابی را طبیعی‌تر می‌کند.

  • پیکربندی: agents.defaults.humanDelay (برای هر عامل از طریق agents.list[].humanDelay بازنویسی کنید).
  • حالت‌ها: off (پیش‌فرض)، natural (800-2500ms)، custom (minMs/maxMs).
  • فقط روی پاسخ‌های بلوکی اعمال می‌شود، نه پاسخ‌های نهایی یا خلاصه‌های ابزار.

«قطعه‌ها را استریم کن یا همه‌چیز را»

این به موارد زیر نگاشت می‌شود:

  • استریم قطعه‌ها: blockStreamingDefault: "on" + blockStreamingBreak: "text_end" (هم‌زمان با پیشرفت منتشر کن). کانال‌های غیر Telegram همچنین به *.blockStreaming: true نیاز دارند.
  • استریم همه‌چیز در پایان: blockStreamingBreak: "message_end" (یک‌بار تخلیه کن، اگر خیلی طولانی باشد احتمالاً چند قطعه).
  • بدون استریم بلوکی: blockStreamingDefault: "off" (فقط پاسخ نهایی).

نکتهٔ کانال: استریم بلوکی خاموش است مگر اینکه *.blockStreaming صراحتاً روی true تنظیم شده باشد. کانال‌ها می‌توانند بدون پاسخ‌های بلوکی، یک پیش‌نمایش زنده (channels.<channel>.streaming) را استریم کنند.

یادآور محل پیکربندی: پیش‌فرض‌های blockStreaming* زیر agents.defaults قرار دارند، نه پیکربندی ریشه.

حالت‌های استریم پیش‌نمایش

کلید معیار: channels.<channel>.streaming

حالت‌ها:

  • off: استریم پیش‌نمایش را غیرفعال می‌کند.
  • partial: یک پیش‌نمایش واحد که با تازه‌ترین متن جایگزین می‌شود.
  • block: پیش‌نمایش در گام‌های قطعه‌شده/افزوده‌شده به‌روزرسانی می‌شود.
  • progress: پیش‌نمایش پیشرفت/وضعیت هنگام تولید، پاسخ نهایی هنگام تکمیل.

streaming.mode: "block" یک حالت استریم پیش‌نمایش برای کانال‌های قابل‌ویرایش مانند Discord و Telegram است. این حالت تحویل بلوکی کانال را در آنجا فعال نمی‌کند. وقتی پاسخ‌های بلوکی عادی می‌خواهید، از streaming.block.enabled یا کلید قدیمی کانال blockStreaming استفاده کنید. Microsoft Teams استثناست: انتقال بلوکی پیش‌نویس پیش‌نمایش ندارد، بنابراین streaming.mode: "block" به‌جای استریم بومی جزئی/پیشرفت، به تحویل بلوکی Teams نگاشت می‌شود.

نگاشت کانال

کانال off partial block progress
Telegram پیش‌نویس پیشرفت قابل‌ویرایش
Discord پیش‌نویس پیشرفت قابل‌ویرایش
Slack
Mattermost
MS Teams استریم پیشرفت بومی

فقط Slack:

  • channels.slack.streaming.nativeTransport فراخوانی‌های API استریم بومی Slack را وقتی channels.slack.streaming.mode="partial" باشد تغییر وضعیت می‌دهد (پیش‌فرض: true).
  • استریم بومی Slack و وضعیت رشتهٔ دستیار Slack به هدف رشتهٔ پاسخ نیاز دارند. پیام‌های مستقیم سطح بالا آن پیش‌نمایش سبک رشته را نشان نمی‌دهند، اما همچنان می‌توانند از پست‌ها و ویرایش‌های پیش‌نمایش پیش‌نویس Slack استفاده کنند.

مهاجرت کلید قدیمی:

  • Telegram: مقدارهای قدیمی streamMode و مقدارهای عددی/بولی streaming شناسایی می‌شوند و مسیرهای سازگاری doctor/config آن‌ها را به streaming.mode مهاجرت می‌کنند.
  • Discord: streamMode + مقدار بولی streaming همچنان نام‌های مستعار زمان اجرا برای enum streaming هستند؛ برای بازنویسی پیکربندی ذخیره‌شده، openclaw doctor --fix را اجرا کنید.
  • Slack: streamMode همچنان نام مستعار زمان اجرا برای streaming.mode است؛ مقدار بولی streaming همچنان نام مستعار زمان اجرا برای streaming.mode به‌همراه streaming.nativeTransport است؛ nativeStreaming قدیمی همچنان نام مستعار زمان اجرا برای streaming.nativeTransport است. برای بازنویسی پیکربندی ذخیره‌شده، openclaw doctor --fix را اجرا کنید.

رفتار زمان اجرا

Telegram:

  • از به‌روزرسانی‌های پیش‌نمایش sendMessage + editMessageText در پیام‌های مستقیم و گروه‌ها/موضوع‌ها استفاده می‌کند.
  • متن نهایی، پیش‌نمایش فعال را درجا ویرایش می‌کند؛ نهایی‌های طولانی از همان پیام برای قطعهٔ اول استفاده می‌کنند و فقط قطعه‌های باقی‌مانده را می‌فرستند.
  • حالت progress پیشرفت ابزار را در یک پیش‌نویس وضعیت قابل‌ویرایش نگه می‌دارد، آن پیش‌نویس را هنگام تکمیل پاک می‌کند، و پاسخ نهایی را از مسیر تحویل عادی می‌فرستد.
  • اگر ویرایش نهایی پیش از تأیید متن کامل‌شده شکست بخورد، OpenClaw از تحویل نهایی عادی استفاده می‌کند و پیش‌نمایش کهنه را پاک‌سازی می‌کند.
  • وقتی استریم بلوکی Telegram صراحتاً فعال باشد، استریم پیش‌نمایش رد می‌شود (برای جلوگیری از استریم دوگانه).
  • /reasoning stream می‌تواند استدلال را در پیش‌نمایشی گذرا بنویسد که پس از تحویل نهایی حذف می‌شود.

Discord:

  • از پیام‌های پیش‌نمایش با ارسال + ویرایش استفاده می‌کند.
  • حالت block از قطعه‌کردن پیش‌نویس (draftChunk) استفاده می‌کند.
  • وقتی استریم بلوکی Discord صراحتاً فعال باشد، استریم پیش‌نمایش رد می‌شود.
  • رسانهٔ نهایی، خطا، و بارهای پاسخ صریح، پیش‌نمایش‌های در انتظار را بدون تخلیهٔ پیش‌نویس جدید لغو می‌کنند، سپس از تحویل عادی استفاده می‌کنند.

Slack:

  • partial می‌تواند وقتی در دسترس باشد از استریم بومی Slack (chat.startStream/append/stop) استفاده کند.
  • block از پیش‌نمایش‌های پیش‌نویس به سبک افزودن استفاده می‌کند.
  • progress از متن پیش‌نمایش وضعیت و سپس پاسخ نهایی استفاده می‌کند.
  • پیام‌های مستقیم سطح بالا بدون رشتهٔ پاسخ، به‌جای استریم بومی Slack از پست‌ها و ویرایش‌های پیش‌نمایش پیش‌نویس استفاده می‌کنند.
  • استریم بومی و پیش‌نمایش پیش‌نویس، پاسخ‌های بلوکی را برای آن نوبت سرکوب می‌کنند، بنابراین یک پاسخ Slack فقط از یک مسیر تحویل استریم می‌شود.
  • بارهای رسانه/خطای نهایی و نهایی‌های پیشرفت، پیام‌های پیش‌نویس دورریختنی ایجاد نمی‌کنند؛ فقط نهایی‌های متن/بلوک که می‌توانند پیش‌نمایش را ویرایش کنند، متن پیش‌نویس در انتظار را تخلیه می‌کنند.

Mattermost:

  • تفکر، فعالیت ابزار، و متن پاسخ جزئی را در یک پست پیش‌نمایش پیش‌نویس واحد استریم می‌کند که وقتی ارسال پاسخ نهایی ایمن باشد درجا نهایی می‌شود.
  • اگر پست پیش‌نمایش حذف شده باشد یا در زمان نهایی‌سازی به هر دلیل در دسترس نباشد، به ارسال یک پست نهایی تازه برمی‌گردد.
  • بارهای رسانه/خطای نهایی، به‌جای تخلیهٔ یک پست پیش‌نمایش موقت، پیش از تحویل عادی به‌روزرسانی‌های پیش‌نمایش در انتظار را لغو می‌کنند.

Matrix:

  • وقتی متن نهایی بتواند از رویداد پیش‌نمایش دوباره استفاده کند، پیش‌نمایش‌های پیش‌نویس درجا نهایی می‌شوند.
  • نهایی‌های فقط‌رسانه، خطا، و عدم‌تطابق هدف پاسخ، پیش از تحویل عادی به‌روزرسانی‌های پیش‌نمایش در انتظار را لغو می‌کنند؛ یک پیش‌نمایش کهنهٔ از پیش قابل‌مشاهده حذف محتوایی می‌شود.

به‌روزرسانی‌های پیش‌نمایش پیشرفت ابزار

استریم پیش‌نمایش همچنین می‌تواند به‌روزرسانی‌های پیشرفت ابزار را شامل شود - خط‌های کوتاه وضعیت مانند «در حال جست‌وجو در وب»، «در حال خواندن فایل»، یا «در حال فراخوانی ابزار» - که هنگام اجرای ابزارها و پیش از پاسخ نهایی، در همان پیام پیش‌نمایش ظاهر می‌شوند. این کار نوبت‌های چندمرحله‌ای ابزار را از نظر بصری زنده نگه می‌دارد، به‌جای اینکه بین نخستین پیش‌نمایش تفکر و پاسخ نهایی ساکت بمانند.

سطوح پشتیبانی‌شده:

  • Discord، Slack، Telegram و Matrix وقتی جریان‌دهی پیش‌نمایش فعال باشد، به‌طور پیش‌فرض پیشرفت ابزار را در ویرایش پیش‌نمایش زنده جریان‌دهی می‌کنند. Microsoft Teams در چت‌های شخصی از جریان پیشرفت بومی خود استفاده می‌کند.
  • Telegram از v2026.4.22 با به‌روزرسانی‌های پیش‌نمایش پیشرفت ابزارِ فعال عرضه شده است؛ فعال نگه داشتن آن‌ها رفتار منتشرشده را حفظ می‌کند.
  • Mattermost از قبل فعالیت ابزار را در تنها پست پیش‌نمایش پیش‌نویس خود ادغام می‌کند (بالا را ببینید).
  • ویرایش‌های پیشرفت ابزار از حالت فعال جریان‌دهی پیش‌نمایش پیروی می‌کنند؛ وقتی جریان‌دهی پیش‌نمایش off باشد یا وقتی جریان‌دهی بلوکی کنترل پیام را به دست گرفته باشد، از آن‌ها صرف‌نظر می‌شود. در Telegram، streaming.mode: "off" فقط نهایی است: گفت‌وگوی عمومی پیشرفت نیز به‌جای تحویل به‌صورت پیام‌های وضعیت مستقل، سرکوب می‌شود، در حالی که درخواست‌های تأیید، payloadهای رسانه‌ای و خطاها همچنان به‌صورت عادی مسیریابی می‌شوند.
  • برای نگه داشتن جریان‌دهی پیش‌نمایش اما پنهان کردن خطوط پیشرفت ابزار، برای آن کانال streaming.preview.toolProgress را روی false تنظیم کنید. برای قابل مشاهده نگه داشتن خطوط پیشرفت ابزار در حالی که متن فرمان/اجرا پنهان است، streaming.preview.commandText را روی "status" یا streaming.progress.commandText را روی "status" تنظیم کنید؛ مقدار پیش‌فرض برای حفظ رفتار منتشرشده "raw" است. این سیاست میان کانال‌های پیش‌نویس/پیشرفت که از نمایش‌دهنده فشرده پیشرفت OpenClaw استفاده می‌کنند مشترک است، از جمله Discord، Matrix، Microsoft Teams، Mattermost، پیش‌نمایش‌های پیش‌نویس Slack، و Telegram. برای غیرفعال کردن کامل ویرایش‌های پیش‌نمایش، streaming.mode را روی off تنظیم کنید.
  • پاسخ‌های نقل‌قول انتخاب‌شده در Telegram یک استثنا هستند: وقتی replyToMode برابر "off" نباشد و متن نقل‌قول انتخاب‌شده وجود داشته باشد، OpenClaw جریان پیش‌نمایش پاسخ را برای آن نوبت رد می‌کند تا خطوط پیش‌نمایش پیشرفت ابزار نتوانند رندر شوند. پاسخ‌های پیام فعلی بدون متن نقل‌قول انتخاب‌شده همچنان جریان‌دهی پیش‌نمایش را نگه می‌دارند. برای جزئیات، مستندات کانال Telegram را ببینید.

خطوط پیشرفت را قابل مشاهده نگه دارید اما متن خام فرمان/اجرا را پنهان کنید:

{
  "channels": {
    "telegram": {
      "streaming": {
        "mode": "partial",
        "preview": {
          "toolProgress": true,
          "commandText": "status"
        }
      }
    }
  }
}

از همین شکل زیر کلید یک کانال پیشرفت فشرده دیگر استفاده کنید، برای مثال channels.discord، channels.matrix، channels.msteams، channels.mattermost، یا پیش‌نمایش‌های پیش‌نویس Slack. برای حالت پیش‌نویس پیشرفت، همین سیاست را زیر streaming.progress قرار دهید:

{
  "channels": {
    "telegram": {
      "streaming": {
        "mode": "progress",
        "progress": {
          "toolProgress": true,
          "commandText": "status"
        }
      }
    }
  }
}

مرتبط