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: تا پایان پیام دستیار صبر کن، سپس خروجی بافرشده را تخلیه کن.
اگر متن بافرشده از maxChars بیشتر باشد، message_end همچنان از قطعهساز استفاده میکند، بنابراین میتواند در پایان چند قطعه منتشر کند.
تحویل رسانه با پخش جریانی بلوک
رسانهٔ جریانی باید از فیلدهای ساختیافتهٔ payload مانند mediaUrl یا
mediaUrls استفاده کند؛ متن جریانی بهعنوان فرمان پیوست تحلیل نمیشود. وقتی پخش
جریانی بلوک رسانه را زود ارسال میکند، OpenClaw آن تحویل را برای آن نوبت به خاطر میسپارد. اگر
payload نهایی دستیار همان URL رسانه را تکرار کند، تحویل نهایی
بهجای ارسال دوبارهٔ پیوست، رسانهٔ تکراری را حذف میکند.
payloadهای نهایی کاملاً تکراری سرکوب میشوند. اگر payload نهایی متن متمایزی پیرامون رسانهای اضافه کند که قبلاً پخش شده است، OpenClaw همچنان متن جدید را ارسال میکند و رسانه را تکتحویلی نگه میدارد. این کار از یادداشتهای صوتی یا فایلهای تکراری در کانالهایی مانند Telegram جلوگیری میکند.
الگوریتم قطعهبندی (کرانهای پایین/بالا)
قطعهبندی بلوک توسط EmbeddedBlockChunker پیادهسازی شده است:
- کران پایین: تا وقتی بافر >=
minCharsنشده منتشر نکن (مگر با اجبار). - کران بالا: تقسیم پیش از
maxCharsرا ترجیح بده؛ اگر اجباری بود، درmaxCharsتقسیم کن. - ترجیح شکست:
paragraph→newline→sentence→whitespace→ شکست سخت. - حصارهای کد: هرگز داخل حصارها تقسیم نکن؛ هنگام اجبار در
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 به هدف رشتهٔ پاسخ نیاز دارند. DMهای سطح بالا آن پیشنمایش رشتهمانند را نشان نمیدهند، اما همچنان میتوانند از پستها و ویرایشهای پیشنمایش پیشنویس Slack استفاده کنند.
مهاجرت کلید قدیمی:
- Telegram: مقادیر قدیمی
streamModeو مقادیر اسکالر/بولیstreamingشناسایی میشوند و مسیرهای سازگاری doctor/پیکربندی آنها را بهstreaming.modeمهاجرت میکنند. - Discord:
streamMode+ بولیstreamingهمچنان aliasهای زمان اجرا برای enumstreamingباقی میمانند؛ برای بازنویسی پیکربندی پایدارشده،openclaw doctor --fixرا اجرا کنید. - Slack:
streamModeهمچنان alias زمان اجرا برایstreaming.modeباقی میماند؛ بولیstreamingهمچنان alias زمان اجرا برایstreaming.modeبهعلاوهٔstreaming.nativeTransportباقی میماند؛nativeStreamingقدیمی همچنان alias زمان اجرا برایstreaming.nativeTransportباقی میماند. برای بازنویسی پیکربندی پایدارشده،openclaw doctor --fixرا اجرا کنید.
رفتار زمان اجرا
Telegram:
- از بهروزرسانیهای پیشنمایش
sendMessage+editMessageTextدر DMها و گروهها/موضوعها استفاده میکند. - پیشنمایشهای کوتاه اولیه همچنان برای تجربهٔ اعلان پوش بهصورت debounce مدیریت میشوند، اما Telegram اکنون آنها را پس از تأخیری محدود محقق میکند تا اجراهای فعال از نظر بصری ساکت نمانند.
- متن نهایی، پیشنمایش فعال را درجا ویرایش میکند؛ نهاییهای طولانی همان پیام را برای قطعهٔ اول دوباره استفاده میکنند و فقط قطعههای باقیمانده را ارسال میکنند.
- حالت
blockپیشنمایش را درstreaming.preview.chunk.maxCharsبه یک پیام جدید میچرخاند (پیشفرض 800، محدود به سقف ویرایش 4096 کاراکتری Telegram)؛ حالتهای دیگر یک پیشنمایش را تا 4096 کاراکتر رشد میدهند. - حالت
progressپیشرفت ابزار را در یک پیشنویس وضعیت قابل ویرایش نگه میدارد، وقتی پخش جریانی پاسخ فعال است اما هنوز خط ابزاری در دسترس نیست برچسب وضعیت را محقق میکند، آن پیشنویس را در پایان پاک میکند، و پاسخ نهایی را از طریق تحویل عادی ارسال میکند. - اگر ویرایش نهایی پیش از تأیید متن کاملشده شکست بخورد، OpenClaw از تحویل نهایی عادی استفاده میکند و پیشنمایش کهنه را پاکسازی میکند.
- وقتی پخش جریانی بلوک Telegram صراحتاً فعال شده باشد، پخش جریانی پیشنمایش رد میشود (برای جلوگیری از پخش جریانی دوگانه).
/reasoning streamمیتواند استدلال را در پیشنمایشی گذرا بنویسد که پس از تحویل نهایی حذف میشود.
Discord:
- از ارسال + ویرایش پیامهای پیشنمایش استفاده میکند.
- حالت
blockاز قطعهبندی پیشنویس (draftChunk) استفاده میکند. - وقتی پخش جریانی بلوک Discord صراحتاً فعال شده باشد، پخش جریانی پیشنمایش رد میشود.
- رسانهٔ نهایی، خطا، و payloadهای پاسخ صریح، پیشنمایشهای در انتظار را بدون تخلیهٔ پیشنویس جدید لغو میکنند و سپس از تحویل عادی استفاده میکنند.
Slack:
partialمیتواند در صورت دسترسبودن از پخش جریانی بومی Slack (chat.startStream/append/stop) استفاده کند.blockاز پیشنمایشهای پیشنویس به سبک افزودن استفاده میکند.progressاز متن پیشنمایش وضعیت استفاده میکند، سپس پاسخ نهایی.- DMهای سطح بالا بدون رشتهٔ پاسخ، بهجای پخش جریانی بومی Slack از پستها و ویرایشهای پیشنمایش پیشنویس استفاده میکنند.
- پخش جریانی بومی و پیشنمایش پیشنویس، پاسخهای بلوکی را برای آن نوبت سرکوب میکنند، بنابراین یک پاسخ Slack فقط از یک مسیر تحویل پخش میشود.
- payloadهای رسانه/خطای نهایی و نهاییهای پیشرفت، پیامهای پیشنویس دورریختنی ایجاد نمیکنند؛ فقط نهاییهای متن/بلوک که میتوانند پیشنمایش را ویرایش کنند، متن پیشنویس در انتظار را تخلیه میکنند.
Mattermost:
- فکر کردن، فعالیت ابزار، و متن پاسخ جزئی را در یک پست پیشنمایش پیشنویس واحد پخش میکند که وقتی ارسال پاسخ نهایی امن باشد، درجا نهایی میشود.
- اگر پست پیشنمایش حذف شده باشد یا در زمان نهاییسازی به هر شکل دیگری در دسترس نباشد، به ارسال یک پست نهایی تازه برمیگردد.
- payloadهای رسانه/خطای نهایی، بهجای تخلیهٔ یک پست پیشنمایش موقت، بهروزرسانیهای پیشنمایش در انتظار را پیش از تحویل عادی لغو میکنند.
Matrix:
- وقتی متن نهایی بتواند رویداد پیشنمایش را دوباره استفاده کند، پیشنمایشهای پیشنویس درجا نهایی میشوند.
- نهاییهای فقطرسانه، خطا، و عدمتطابق هدف پاسخ، پیش از تحویل عادی بهروزرسانیهای پیشنمایش در انتظار را لغو میکنند؛ پیشنمایش کهنهای که از قبل دیده میشود، redacted میشود.
بهروزرسانیهای پیشنمایش پیشرفت ابزار
پخش جریانی پیشنمایش همچنین میتواند شامل بهروزرسانیهای پیشرفت ابزار باشد - خطهای وضعیت کوتاهی مانند «جستوجو در وب»، «خواندن فایل»، یا «فراخوانی ابزار» - که هنگام اجرای ابزارها، پیش از پاسخ نهایی، در همان پیام پیشنمایش ظاهر میشوند. در حالت app-server Codex، پیامهای مقدمه/توضیح Codex از همین مسیر پیشنمایش استفاده میکنند، بنابراین یادداشتهای پیشرفت کوتاه مانند «دارم بررسی میکنم...» میتوانند بدون تبدیلشدن به بخشی از پاسخ نهایی، در پیشنویس قابل ویرایش پخش شوند. این کار نوبتهای چندمرحلهای ابزار را از نظر بصری زنده نگه میدارد، نه اینکه بین نخستین پیشنمایش فکر کردن و پاسخ نهایی ساکت بمانند.
ابزارهای طولانیاجرا ممکن است پیش از بازگشت، پیشرفت نوعدار منتشر کنند. برای مثال،
web_fetch هنگام شروع یک تایمر پنجثانیهای را مسلح میکند: اگر واکشی همچنان
در انتظار باشد، پیشنمایش میتواند Fetching page content... را نشان دهد؛ اگر واکشی پیش از آن
تمام یا لغو شود، هیچ خط پیشرفتی منتشر نمیشود. نتیجهٔ نهایی بعدی ابزار
همچنان بهصورت عادی به مدل تحویل داده میشود.
سطوح پشتیبانیشده:
- Discord، Slack، Telegram و Matrix بهطور پیشفرض، زمانی که جریانسازی پیشنمایش فعال است، بهروزرسانیهای پیشرفت ابزار و مقدمههای Codex را در ویرایش پیشنمایش زنده جاری میکنند. 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 را ببینید.
مسیر پیشرفت توضیحات
فراتر از پیشرفت ابزار، رندرکننده پیشرفت فشرده میتواند یک مسیر دیگر را در پیشنویس نمایش دهد:
streaming.progress.commentary— توضیحات پیش از ابزار مدل (💬) را رندر میکند — روایت کوتاه «بررسی میکنم… سپس…» — که در پیشنویس پیشرفت با خطوط ابزار درهمگذاری میشود.
{ "channels": { "discord": { "streaming": { "mode": "progress", "progress": { "commentary": true } } } }}خطوط پیشرفت را قابلمشاهده نگه دارید اما متن خام دستور/اجرا را پنهان کنید:
{ "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" } } } }}مرتبط
- بازآرایی چرخه عمر پیام - طراحی هدف برای پیشنمایش، ویرایش، جریانسازی و نهاییسازی مشترک
- پیشنویسهای پیشرفت - پیامهای کارِ در جریانِ قابلمشاهده که در طول نوبتهای طولانی بهروزرسانی میشوند
- پیامها - چرخه عمر و تحویل پیام
- تلاش دوباره - رفتار تلاش دوباره هنگام شکست تحویل
- کانالها - پشتیبانی جریانسازی برای هر کانال