Messages and delivery

صف فرمان‌ها

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

چرا

  • اجراهای پاسخ خودکار ممکن است پرهزینه باشند (فراخوانی‌های LLM) و وقتی چند پیام ورودی با فاصله زمانی کوتاه می‌رسند، ممکن است با هم تداخل کنند.
  • اجرای ترتیبی از رقابت بر سر منابع مشترک (فایل‌های نشست، گزارش‌ها، ورودی استاندارد CLI) جلوگیری می‌کند و احتمال مواجهه با محدودیت نرخ سرویس‌های بالادستی را کاهش می‌دهد.

نحوه کار

  • یک صف FIFO آگاه از مسیر، هر مسیر را با سقف هم‌زمانی قابل‌تنظیم تخلیه می‌کند (پیش‌فرض برای مسیرهای پیکربندی‌نشده ۱ است؛ پیش‌فرض main برابر ۴ و subagent برابر ۸ است).
  • runEmbeddedAgent بر اساس کلید نشست (مسیر session:<key>) در صف قرار می‌گیرد تا تضمین شود در هر نشست فقط یک اجرای فعال وجود دارد.
  • سپس هر اجرای نشست در یک مسیر سراسری (به‌طور پیش‌فرض main) قرار می‌گیرد تا موازی‌سازی کلی به‌وسیله agents.defaults.maxConcurrent محدود شود.
  • وقتی ثبت گزارش تفصیلی فعال است، اجراهای در صف اگر پیش از شروع بیش از حدود ۲ ثانیه منتظر مانده باشند، اعلان کوتاهی منتشر می‌کنند.
  • نشانگرهای در حال تایپ همچنان بلافاصله هنگام قرارگیری در صف فعال می‌شوند (اگر کانال از آن پشتیبانی کند)، بنابراین تجربه کاربر هنگام انتظار اجرا برای رسیدن نوبتش تغییری نمی‌کند.

پیش‌فرض‌ها

وقتی تنظیم نشده باشند، همه سطوح کانال‌های ورودی از این مقادیر استفاده می‌کنند:

  • mode: "steer"
  • debounceMs: 500
  • cap: 20
  • drop: "summarize"

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

حالت‌های صف

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

  • steer: پیام‌ها را به زمان‌اجرای فعال تزریق می‌کند. OpenClaw همه پیام‌های هدایت در انتظار را پس از آنکه نوبت فعلی دستیار اجرای فراخوانی‌های ابزار خود را به پایان رساند و پیش از فراخوانی بعدی LLM تحویل می‌دهد؛ سرور برنامه Codex یک turn/steer دسته‌ای دریافت می‌کند. اگر اجرا به‌طور فعال در حال پخش جریانی نباشد یا هدایت در دسترس نباشد، OpenClaw پیش از آغاز درخواست منتظر پایان اجرای فعال می‌ماند.
  • followup: هدایت نمی‌کند. هر پیام را برای نوبت بعدی عامل، پس از پایان اجرای جاری، در صف قرار می‌دهد.
  • collect: هدایت نمی‌کند. پیام‌های در صف را پس از پنجره سکوت در یک نوبت پیگیری واحد ادغام می‌کند. اگر پیام‌ها کانال‌ها/رشته‌های متفاوتی را هدف بگیرند، برای حفظ مسیریابی به‌صورت جداگانه تخلیه می‌شوند.
  • interrupt: اجرای فعال آن نشست را لغو می‌کند و سپس جدیدترین پیام را اجرا می‌کند.

برای زمان‌بندی و رفتار وابستگی ویژه هر زمان‌اجرا، به صف هدایت مراجعه کنید. برای فرمان صریح /steer <message>، به هدایت مراجعه کنید.

از طریق messages.queue به‌صورت سراسری یا برای هر کانال پیکربندی کنید:

json5
{  messages: {    queue: {      mode: "steer",      debounceMs: 500,      cap: 20,      drop: "summarize",      byChannel: { discord: "collect" },    },  },}

گزینه‌های صف

گزینه‌ها بر تحویل موارد در صف اعمال می‌شوند. debounceMs در حالت steer پنجره سکوت هدایت Codex را نیز تعیین می‌کند:

  • debounceMs: پنجره سکوت پیش از تخلیه پیگیری‌های در صف یا دسته‌های جمع‌آوری‌شده؛ در حالت steer در Codex، پنجره سکوت پیش از ارسال turn/steer دسته‌ای. اعداد بدون واحد بر حسب میلی‌ثانیه هستند؛ گزینه‌های /queue واحدهای ms، s، m، h و d را می‌پذیرند.
  • cap: حداکثر تعداد پیام‌های در صف برای هر نشست. مقادیر کمتر از 1 نادیده گرفته می‌شوند.
  • drop: "summarize" (پیش‌فرض): در صورت نیاز قدیمی‌ترین موارد صف را حذف می‌کند، خلاصه‌های فشرده را نگه می‌دارد و آن‌ها را به‌صورت یک درخواست پیگیری مصنوعی تزریق می‌کند.
  • drop: "old": در صورت نیاز قدیمی‌ترین موارد صف را بدون حفظ خلاصه‌ها حذف می‌کند.
  • drop: "new": وقتی صف از قبل پر است، جدیدترین پیام را رد می‌کند.

پیش‌فرض‌ها: debounceMs: 500، cap: 20، drop: summarize.

هدایت و پخش جریانی

وقتی پخش جریانی کانال روی partial یا block تنظیم شده باشد، ممکن است هدایت تا رسیدن اجرای فعال به مرزهای زمان‌اجرا، به‌شکل چند پاسخ کوتاه و قابل‌مشاهده ظاهر شود:

  • partial: ممکن است پیش‌نمایش زودتر نهایی شود و پس از پذیرفته‌شدن هدایت، پیش‌نمایش جدیدی آغاز شود.
  • block: بلوک‌هایی به‌اندازه پیش‌نویس می‌توانند ظاهر ترتیبی مشابهی ایجاد کنند.
  • بدون پخش جریانی، وقتی زمان‌اجرا نتواند هدایت در همان نوبت را بپذیرد، هدایت پس از اجرای فعال به یک پیگیری تبدیل می‌شود.

steer ابزارهای در حال اجرا را لغو نمی‌کند. وقتی جدیدترین پیام باید اجرای جاری را لغو کند، از /queue interrupt استفاده کنید.

تقدم

OpenClaw برای انتخاب حالت، این ترتیب را اعمال می‌کند:

  1. بازنویسی درون‌خطی یا ذخیره‌شده /queue برای هر نشست.
  2. messages.queue.byChannel.<channel>.
  3. messages.queue.mode.
  4. پیش‌فرض steer.

برای گزینه‌ها، گزینه‌های درون‌خطی یا ذخیره‌شده /queue بر پیکربندی اولویت دارند. سپس تأخیر ویژه کانال (messages.queue.debounceMsByChannel)، پیش‌فرض‌های تأخیر Plugin، گزینه‌های سراسری messages.queue و پیش‌فرض‌های داخلی، به همین ترتیب اعمال می‌شوند. cap و drop گزینه‌های سراسری/نشست هستند، نه کلیدهای پیکربندی مختص کانال.

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

  • برای ذخیره حالت صف نشست جاری، /queue <steer|followup|collect|interrupt> را به‌صورت یک فرمان مستقل ارسال کنید.
  • گزینه‌ها را می‌توان ترکیب کرد: /queue collect debounce:0.5s cap:25 drop:summarize
  • /queue default یا /queue reset بازنویسی نشست را پاک می‌کند.

لغو نوبت‌های در صف

تا زمانی که یک درخواست در صف پیگیری/جمع‌آوری قرار دارد (برای مثال، یک chat.send از TUI یا گپ وب که هنگام فعال‌بودن نوبتی دیگر می‌رسد)، Gateway برای runId آن کارخواه یک شناسه لغو تحت مالکیت Gateway نگه می‌دارد تا زمانی که محتوای در صف اجرا یا حذف شود. این شناسه، محتوایی را که در یک خلاصه سرریز ادغام شده است نیز دنبال می‌کند.

  • chat.abort با یک runId مشخص، در صورتی که درخواست‌کننده مجاز باشد، آن نوبت را تا زمانی که هنوز در صف است لغو می‌کند (با همان قواعد مالکیت اجراهای فعال).
  • chat.abort برای یک نشست بدون runId ابتدا نوبت‌های مجاز در صف را لغو می‌کند و سپس اجراهای فعال مجاز را لغو می‌کند. این ترتیب مانع می‌شود تخلیه صف، کار را به نشستی با توقف نیمه‌کاره منتقل کند.
  • پاک‌کردن کل صف نشست بدون بررسی جداگانه هر درخواست‌کننده، مسیر توقف برای نشست‌های چندمالکی نیست.
  • انتظارهای در صف در sessions.list به‌عنوان اجراهای فعال عامل نمایش داده نمی‌شوند و مالک معنای مهلت زمانی اجرای فعال نیستند؛ فقط مرحله فعال چنین معنایی دارد.

کارخواه‌ها (از جمله TUI) درخواست‌های میان اجرا را ارسال می‌کنند و اجازه می‌دهند Gateway حالت صف را اعمال کند. Esc//stop از لغو در محدوده نشست استفاده می‌کند تا گم‌شدن دستگیره‌های محلی باعث نشود یک درخواست همچنان در صف باقی بماند و اجرا شود.

دامنه و تضمین‌ها

  • بر اجراهای عامل پاسخ خودکار در همه کانال‌های ورودی که از خط لوله پاسخ Gateway استفاده می‌کنند اعمال می‌شود (وب WhatsApp، Telegram، Slack، Discord، Signal، iMessage، گپ وب و غیره).
  • مسیر پیش‌فرض (main) در سراسر پردازه برای ورودی‌ها و Heartbeatهای اصلی مشترک است؛ برای اجرای هم‌زمان چند نشست، agents.defaults.maxConcurrent را تنظیم کنید.
  • ممکن است مسیرهای دیگری نیز وجود داشته باشند (برای مثال cron، cron-nested، nested و subagent) تا کارهای پس‌زمینه بدون مسدودکردن پاسخ‌های ورودی به‌صورت موازی اجرا شوند. نوبت‌های عامل Cron ایزوله‌شده هنگام استفاده اجرای عامل درونی‌شان از cron-nested، یک جایگاه cron را نگه می‌دارند؛ هر دو از cron.maxConcurrentRuns استفاده می‌کنند. جریان‌های مشترک غیر Cron از نوع nested رفتار مسیر خود را حفظ می‌کنند. این اجراهای جداشده به‌عنوان وظایف پس‌زمینه ردیابی می‌شوند.
  • مسیرهای هر نشست تضمین می‌کنند که در هر لحظه فقط یک اجرای عامل به نشست مشخصی دسترسی داشته باشد.
  • بدون وابستگی خارجی یا رشته‌های کارگر پس‌زمینه؛ فقط TypeScript و promiseها.

عیب‌یابی

  • اگر به نظر می‌رسد فرمان‌ها گیر کرده‌اند، گزارش‌های تفصیلی را فعال کنید و برای تأیید تخلیه‌شدن صف به‌دنبال خطوط "queued for ...ms" بگردید.
  • اجراهای سرور برنامه Codex که نوبتی را می‌پذیرند و سپس انتشار پیشرفت را متوقف می‌کنند، به‌وسیله سازگارکننده Codex متوقف می‌شوند تا مسیر نشست فعال به‌جای انتظار برای مهلت زمانی اجرای بیرونی آزاد شود.
  • وقتی عیب‌یابی فعال است، نشست‌هایی که پس از diagnostics.stuckSessionWarnMs همچنان در وضعیت processing می‌مانند و هیچ پیشرفتی در پاسخ، ابزار، وضعیت، بلوک یا ACP برای آن‌ها مشاهده نشده است، بر اساس فعالیت جاری دسته‌بندی می‌شوند:
    • کار فعال با پیشرفت اخیر با عنوان session.long_running ثبت می‌شود. فراخوانی‌های بی‌صدای مدل که مالک دارند نیز تا diagnostics.stuckSessionAbortMs در وضعیت session.long_running باقی می‌مانند تا ارائه‌دهندگان کند یا بدون پخش جریانی زودهنگام متوقف‌شده گزارش نشوند.
    • کار فعال بدون پیشرفت اخیر با عنوان session.stalled ثبت می‌شود؛ فراخوانی‌های مدل دارای مالک، فراخوانی‌های ابزار مسدودشده و اجراهای تعبیه‌شده متوقف‌شده، در آستانه لغو یا پس از آن به session.stalled تغییر وضعیت می‌دهند. فعالیت کهنه مدل/ابزار بدون مالک به‌عنوان اجرای طولانی پنهان نمی‌شود.
    • session.stuck برای ثبت وضعیت کهنه و قابل‌بازیابی نشست، از جمله نشست‌های بیکار در صف با فعالیت کهنه مدل/ابزار بدون مالک، رزرو شده است.
    • session.stuck همیشه بازیابی‌ای را فعال می‌کند که می‌تواند مسیر نشست تحت‌تأثیر را آزاد کند. دسته‌بندی session.stalled پس از diagnostics.stuckSessionAbortMs (فراخوانی ابزار مسدودشده، فراخوانی مدل متوقف‌شده یا اجرای تعبیه‌شده متوقف‌شده) نیز می‌تواند بازیابی از طریق لغو فعال را راه‌اندازی کند؛ بنابراین هر دو دسته‌بندی می‌توانند صف را از حالت گیرکرده خارج کنند، نه فقط session.stuck.
    • خطوط گزارش هشدار تکراری session.stuck و session.long_running تا زمانی که نشست بدون تغییر بماند، با عقب‌نشینی نمایی منتشر می‌شوند؛ تلاش‌های بازیابی بدون توجه به این عقب‌نشینی، در هر تیک Heartbeat همچنان اجرا می‌شوند.

مرتبط

Was this useful?
On this page

On this page