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

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

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

لماذا

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

كيف يعمل

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

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

يمكن للرسائل الواردة توجيه التشغيل الحالي، أو الانتظار لدورة لاحقة، أو القيام بالأمرين معًا:
  • steer: الإدراج فورًا في التشغيل الحالي (يلغي استدعاءات الأدوات المعلّقة بعد حدّ الأداة التالي). إذا لم يكن هناك بثّ، يعود إلى المتابعة اللاحقة.
  • followup: الإدراج لدورة الوكيل التالية بعد انتهاء التشغيل الحالي.
  • collect: دمج جميع الرسائل المُدرَجة في دورة متابعة واحدة (الافتراضي). إذا استهدفت الرسائل قنوات/سلاسل مختلفة، تُصرَّف بشكل منفصل للحفاظ على التوجيه.
  • steer-backlog (المعروف أيضًا باسم steer+backlog): التوجيه الآن مع الاحتفاظ بالرسالة لدورة متابعة.
  • interrupt (قديمة): إيقاف التشغيل النشط لتلك الجلسة، ثم تشغيل أحدث رسالة.
  • queue (اسم بديل قديم): مماثل لـ steer.
يعني «توجيه المتراكم» أنه يمكنك الحصول على استجابة متابعة بعد التشغيل المُوجَّه، لذا قد تبدو واجهات البث وكأنها مكررة. يُفضَّل 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 عندما يعود إلى المتابعة):
  • debounceMs: الانتظار حتى الهدوء قبل بدء دورة متابعة (يمنع «تابع، تابع»).
  • cap: الحد الأقصى لعدد الرسائل المُدرَجة لكل جلسة.
  • drop: سياسة الفائض (old، new، summarize).
يقوم «التلخيص» بالاحتفاظ بقائمة نقطية قصيرة من الرسائل المُسقَطة ويُدرِجها كمحفّز متابعة اصطناعي. الافتراضيات: 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) على مستوى العملية للرسائل الواردة + نبضات القلب الرئيسية؛ اضبط agents.defaults.maxConcurrent للسماح بتوازي عدة جلسات.
  • قد توجد ممرات إضافية (مثل cron وsubagent) بحيث يمكن للمهام الخلفية العمل بالتوازي دون حجب الردود الواردة.
  • تضمن الممرات لكل جلسة أن تشغيل وكيل واحد فقط يلمس جلسة معينة في أي وقت.
  • لا توجد تبعيات خارجية أو خيوط عمّال في الخلفية؛ TypeScript خالص + وعود.

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

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