الانتقال إلى المحتوى الرئيسي

طابور الأوامر (2026-01-16)

نقوم بتسلسل تشغيلات الرد التلقائي الواردة (جميع القنوات) عبر طابور صغير داخل العملية لمنع تصادم تشغيلات الوكيل المتعددة، مع الاستمرار في السماح بالتوازي الآمن عبر الجلسات.

لماذا

  • قد تكون تشغيلات الرد التلقائي مكلفة (استدعاءات LLM) ويمكن أن تتصادم عندما تصل عدة رسائل واردة في وقت متقارب.
  • يؤدي التسلسل إلى تجنب التنافس على الموارد المشتركة (ملفات الجلسة، والسجلات، وCLI stdin) ويقلل احتمال حدود المعدل في المصادر العليا.

كيف يعمل

  • يقوم طابور FIFO مدرك للمسارات بتصريف كل مسار بحد تزامن قابل للتهيئة (الافتراضي 1 للمسارات غير المهيأة؛ وmain افتراضيه 4، وsubagent افتراضيه 8).
  • يقوم runEmbeddedPiAgent بالإدراج في الطابور حسب مفتاح الجلسة (المسار session:<key>) لضمان وجود تشغيل نشط واحد فقط لكل جلسة.
  • ثم يتم إدراج كل تشغيل جلسة في مسار عام (main افتراضيًا) بحيث يُقيَّد التوازي الإجمالي بواسطة agents.defaults.maxConcurrent.
  • عند تمكين السجل المفصل، تصدر التشغيلات الموجودة في الطابور إشعارًا قصيرًا إذا انتظرت أكثر من نحو ثانيتين قبل البدء.
  • لا تزال مؤشرات الكتابة تُرسل فور الإدراج في الطابور (عند الدعم من القناة) بحيث تبقى تجربة المستخدم دون تغيير أثناء انتظار الدور.

أوضاع الطابور (لكل قناة)

يمكن للرسائل الواردة توجيه التشغيل الحالي، أو الانتظار لدورة متابعة، أو فعل الأمرين معًا:
  • steer: يحقن الرسالة فورًا في التشغيل الحالي (ويلغي استدعاءات الأدوات المعلقة بعد حد الأداة التالي). وإذا لم يكن هناك بث متدفق، يعود إلى followup.
  • followup: يدرج الرسالة في الطابور لدورة الوكيل التالية بعد انتهاء التشغيل الحالي.
  • collect: يدمج جميع الرسائل الموجودة في الطابور في دورة متابعة واحدة (الافتراضي). وإذا استهدفت الرسائل قنوات/سلاسل مختلفة، يتم تصريفها بشكل فردي للحفاظ على التوجيه.
  • steer-backlog ‏(المعروف أيضًا باسم steer+backlog): يوجّه الآن ويحتفظ بالرسالة أيضًا لدورة متابعة.
  • interrupt ‏(قديم): يجهض التشغيل النشط لتلك الجلسة، ثم يشغّل أحدث رسالة.
  • queue ‏(اسم بديل قديم): يساوي steer.
يعني steer-backlog أنه يمكنك الحصول على استجابة متابعة بعد التشغيل الموجّه، لذلك قد تبدو الأسطح المتدفقة وكأنها مكررة. فضّل collect/steer إذا كنت تريد استجابة واحدة لكل رسالة واردة. أرسل /queue collect كأمر مستقل (لكل جلسة) أو اضبط messages.queue.byChannel.discord: "collect". الافتراضيات (عند عدم ضبطها في الإعدادات):
  • جميع الأسطح → collect
قم بالتهيئة عالميًا أو لكل قناة عبر messages.queue:
{
  messages: {
    queue: {
      mode: "collect",
      debounceMs: 1000,
      cap: 20,
      drop: "summarize",
      byChannel: { discord: "collect" },
    },
  },
}

خيارات الطابور

تنطبق الخيارات على followup وcollect وsteer-backlog (وأيضًا على steer عندما يعود إلى followup):
  • debounceMs: انتظر فترة هدوء قبل بدء دورة المتابعة (لمنع “تابع، تابع”).
  • cap: الحد الأقصى للرسائل الموجودة في الطابور لكل جلسة.
  • drop: سياسة التجاوز (old أو new أو summarize).
تحتفظ summarize بقائمة نقطية قصيرة للرسائل التي تم إسقاطها وتحقنها كـ prompt متابعة اصطناعي. الافتراضيات: debounceMs: 1000 وcap: 20 وdrop: summarize.

تجاوزات لكل جلسة

  • أرسل /queue <mode> كأمر مستقل لتخزين الوضع للجلسة الحالية.
  • يمكن دمج الخيارات: /queue collect debounce:2s cap:25 drop:summarize
  • يقوم /queue default أو /queue reset بمسح تجاوز الجلسة.

النطاق والضمانات

  • ينطبق على تشغيلات الوكيل ذات الرد التلقائي عبر جميع القنوات الواردة التي تستخدم خط أنابيب الرد في gateway ‏(WhatsApp web وTelegram وSlack وDiscord وSignal وiMessage وwebchat وغيرها).
  • يكون المسار الافتراضي (main) على مستوى العملية لكل من الوارد + heartbeats الرئيسية؛ اضبط agents.defaults.maxConcurrent للسماح بعدة جلسات بالتوازي.
  • قد توجد مسارات إضافية (مثل cron وsubagent) بحيث يمكن للمهام الخلفية العمل بالتوازي من دون حظر الردود الواردة. ويتم تتبع هذه التشغيلات المنفصلة كـ مهام خلفية.
  • تضمن المسارات الخاصة بكل جلسة أن تشغيل وكيل واحدًا فقط يلامس جلسة معينة في كل مرة.
  • لا توجد تبعيات خارجية أو خيوط عامل في الخلفية؛ فقط TypeScript + وعود.

استكشاف الأخطاء وإصلاحها

  • إذا بدت الأوامر عالقة، فقم بتمكين السجلات المفصلة وابحث عن أسطر “queued for …ms” للتأكد من أن الطابور يُصرَّف.
  • إذا كنت بحاجة إلى عمق الطابور، فقم بتمكين السجلات المفصلة وراقب أسطر توقيت الطابور.