Messages and delivery

คิวคำสั่ง

OpenClaw จัดลำดับการรันตอบกลับอัตโนมัติขาเข้า (ทุกช่องทาง) ผ่านคิวขนาดเล็กภายในโปรเซส เพื่อป้องกันไม่ให้การรันเอเจนต์หลายรายการชนกัน ขณะเดียวกันยังคงอนุญาตให้ประมวลผลแบบขนานระหว่างเซสชันได้อย่างปลอดภัย

เหตุผล

  • การรันตอบกลับอัตโนมัติอาจใช้ทรัพยากรมาก (การเรียก LLM) และอาจชนกันเมื่อมีข้อความขาเข้าหลายข้อความมาถึงในเวลาไล่เลี่ยกัน
  • การจัดลำดับช่วยหลีกเลี่ยงการแย่งใช้ทรัพยากรร่วมกัน (ไฟล์เซสชัน บันทึก และอินพุตมาตรฐานของ CLI) และลดโอกาสที่จะติดข้อจำกัดอัตราการเรียกใช้ของระบบต้นทาง

วิธีการทำงาน

  • คิว FIFO ที่รับรู้เลนจะระบายงานของแต่ละเลนตามขีดจำกัดการทำงานพร้อมกันที่กำหนดได้ (ค่าเริ่มต้นคือ 1 สำหรับเลนที่ไม่ได้กำหนดค่า โดย main มีค่าเริ่มต้นเป็น 4 และ subagent เป็น 8)
  • runEmbeddedAgent เข้าคิวตาม คีย์เซสชัน (เลน session:<key>) เพื่อรับประกันว่าจะมีการรันที่ทำงานอยู่เพียงรายการเดียวต่อเซสชัน
  • จากนั้นการรันของแต่ละเซสชันจะถูกเข้าคิวใน เลนส่วนกลาง (ค่าเริ่มต้นคือ main) เพื่อจำกัดการทำงานพร้อมกันโดยรวมตาม agents.defaults.maxConcurrent
  • เมื่อเปิดใช้การบันทึกแบบละเอียด การรันที่อยู่ในคิวจะแสดงข้อความแจ้งสั้น ๆ หากรอนานกว่า ~2 วินาทีก่อนเริ่มทำงาน
  • ตัวบ่งชี้การพิมพ์ยังคงทำงานทันทีเมื่อเข้าคิว (หากช่องทางรองรับ) ดังนั้นประสบการณ์ของผู้ใช้จึงไม่เปลี่ยนแปลงระหว่างที่การรนรอถึงลำดับของตน

ค่าเริ่มต้น

เมื่อไม่ได้กำหนดค่า พื้นผิวช่องทางขาเข้าทั้งหมดจะใช้:

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

การชี้นำภายในเทิร์นเดียวกันเป็นค่าเริ่มต้น พรอมต์ที่มาถึงระหว่างการรันจะถูกแทรกเข้าไปในรันไทม์ที่ทำงานอยู่ หากการรันนั้นรับการชี้นำได้ จึงไม่มีการเริ่มการรันเซสชันที่สอง หากการรันที่ทำงานอยู่รับการชี้นำไม่ได้ OpenClaw จะรอให้การรันนั้นเสร็จสิ้นก่อนเริ่มพรอมต์

โหมดคิว

/queue ควบคุมการจัดการข้อความขาเข้าปกติขณะที่เซสชันมีการรันที่ทำงานอยู่แล้ว:

  • steer: แทรกข้อความเข้าไปในรันไทม์ที่ทำงานอยู่ OpenClaw จะส่งข้อความชี้นำที่รออยู่ทั้งหมด หลังจากเทิร์นปัจจุบันของผู้ช่วยเรียกใช้เครื่องมือเสร็จสิ้น และก่อนการเรียก LLM ครั้งถัดไป ส่วน Codex app-server จะได้รับ 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 ยังกำหนดช่วงเงียบของการชี้นำ Codex ในโหมด steer:

  • 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 จะล้างการแทนค่าของเซสชัน

การยกเลิกเทิร์นที่อยู่ในคิว

ขณะที่พรอมต์อยู่ในคิว followup/collect (เช่น chat.send จาก TUI หรือ เว็บแชตที่มาถึงขณะที่อีกเทิร์นกำลังทำงาน) Gateway จะเก็บ ข้อมูลระบุการยกเลิกที่ Gateway เป็นเจ้าของ สำหรับ runId ของไคลเอนต์นั้นไว้จนกว่าเนื้อหาในคิว จะทำงานหรือถูกทิ้ง ข้อมูลระบุดังกล่าวจะติดตามเนื้อหาที่ถูกรวมเข้าใน ข้อมูลสรุปเมื่อล้น

  • 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 ขณะที่การดำเนินการเอเจนต์ภายในใช้ cron-nested โดยทั้งสองใช้ cron.maxConcurrentRuns โฟลว์ nested ที่ใช้ร่วมกันและไม่ใช่ Cron จะคงพฤติกรรมของเลนตนเอง การรันแบบแยกเหล่านี้จะถูกติดตามเป็น งานเบื้องหลัง
  • เลนต่อเซสชันรับประกันว่าจะมีการรันเอเจนต์เพียงรายการเดียวที่เข้าถึงเซสชันหนึ่ง ๆ ในแต่ละครั้ง
  • ไม่มีการขึ้นต่อกันภายนอกหรือเธรดผู้ปฏิบัติงานเบื้องหลัง ใช้ TypeScript และพรอมิสล้วน

การแก้ไขปัญหา

  • หากดูเหมือนว่าคำสั่งค้าง ให้เปิดใช้บันทึกแบบละเอียดและมองหาบรรทัด "queued for ...ms" เพื่อยืนยันว่าคิวกำลังระบาย
  • การรัน Codex app-server ที่รับเทิร์นแล้วหยุดส่งความคืบหน้า จะถูกอะแดปเตอร์ Codex ขัดจังหวะ เพื่อให้เลนเซสชันที่ทำงานอยู่ถูกปล่อย แทนที่จะรอการหมดเวลาของการรันภายนอก
  • เมื่อเปิดใช้การวินิจฉัย เซสชันที่ยังคงอยู่ในสถานะ processing นานกว่า diagnostics.stuckSessionWarnMs โดยไม่พบความคืบหน้าของการตอบกลับ เครื่องมือ สถานะ บล็อก หรือ ACP จะถูกจำแนกตามกิจกรรมปัจจุบัน:
    • งานที่ทำงานอยู่และมีความคืบหน้าเมื่อไม่นานมานี้จะถูกบันทึกเป็น session.long_running การเรียกโมเดลแบบเงียบที่มีเจ้าของจะยังคงเป็น session.long_running จนถึง diagnostics.stuckSessionAbortMs เช่นกัน เพื่อไม่ให้ผู้ให้บริการที่ช้าหรือไม่มีการสตรีมถูกรายงานว่าหยุดชะงักเร็วเกินไป
    • งานที่ทำงานอยู่แต่ไม่มีความคืบหน้าเมื่อไม่นานมานี้จะถูกบันทึกเป็น 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