Messages and delivery
คิวคำสั่ง
OpenClaw จัดลำดับการรันตอบกลับอัตโนมัติขาเข้า (ทุกช่องทาง) ผ่านคิวขนาดเล็กภายในโปรเซส เพื่อป้องกันไม่ให้การรันเอเจนต์หลายรายการชนกัน ขณะเดียวกันยังคงอนุญาตให้ประมวลผลแบบขนานระหว่างเซสชันได้อย่างปลอดภัย
เหตุผล
- การรันตอบกลับอัตโนมัติอาจใช้ทรัพยากรมาก (การเรียก LLM) และอาจชนกันเมื่อมีข้อความขาเข้าหลายข้อความมาถึงในเวลาไล่เลี่ยกัน
- การจัดลำดับช่วยหลีกเลี่ยงการแย่งใช้ทรัพยากรร่วมกัน (ไฟล์เซสชัน บันทึก และอินพุตมาตรฐานของ CLI) และลดโอกาสที่จะติดข้อจำกัดอัตราการเรียกใช้ของระบบต้นทาง
วิธีการทำงาน
- คิว FIFO ที่รับรู้เลนจะระบายงานของแต่ละเลนตามขีดจำกัดการทำงานพร้อมกันที่กำหนดได้ (ค่าเริ่มต้นคือ 1 สำหรับเลนที่ไม่ได้กำหนดค่า โดย
mainมีค่าเริ่มต้นเป็น 4 และsubagentเป็น 8) runEmbeddedAgentเข้าคิวตาม คีย์เซสชัน (เลนsession:<key>) เพื่อรับประกันว่าจะมีการรันที่ทำงานอยู่เพียงรายการเดียวต่อเซสชัน- จากนั้นการรันของแต่ละเซสชันจะถูกเข้าคิวใน เลนส่วนกลาง (ค่าเริ่มต้นคือ
main) เพื่อจำกัดการทำงานพร้อมกันโดยรวมตามagents.defaults.maxConcurrent - เมื่อเปิดใช้การบันทึกแบบละเอียด การรันที่อยู่ในคิวจะแสดงข้อความแจ้งสั้น ๆ หากรอนานกว่า ~2 วินาทีก่อนเริ่มทำงาน
- ตัวบ่งชี้การพิมพ์ยังคงทำงานทันทีเมื่อเข้าคิว (หากช่องทางรองรับ) ดังนั้นประสบการณ์ของผู้ใช้จึงไม่เปลี่ยนแปลงระหว่างที่การรนรอถึงลำดับของตน
ค่าเริ่มต้น
เมื่อไม่ได้กำหนดค่า พื้นผิวช่องทางขาเข้าทั้งหมดจะใช้:
mode: "steer"debounceMs: 500cap: 20drop: "summarize"
การชี้นำภายในเทิร์นเดียวกันเป็นค่าเริ่มต้น พรอมต์ที่มาถึงระหว่างการรันจะถูกแทรกเข้าไปในรันไทม์ที่ทำงานอยู่ หากการรันนั้นรับการชี้นำได้ จึงไม่มีการเริ่มการรันเซสชันที่สอง หากการรันที่ทำงานอยู่รับการชี้นำไม่ได้ OpenClaw จะรอให้การรันนั้นเสร็จสิ้นก่อนเริ่มพรอมต์
โหมดคิว
/queue ควบคุมการจัดการข้อความขาเข้าปกติขณะที่เซสชันมีการรันที่ทำงานอยู่แล้ว:
steer: แทรกข้อความเข้าไปในรันไทม์ที่ทำงานอยู่ OpenClaw จะส่งข้อความชี้นำที่รออยู่ทั้งหมด หลังจากเทิร์นปัจจุบันของผู้ช่วยเรียกใช้เครื่องมือเสร็จสิ้น และก่อนการเรียก LLM ครั้งถัดไป ส่วน Codex app-server จะได้รับturn/steerแบบรวมชุดหนึ่งครั้ง หากการรันไม่ได้กำลังสตรีมอยู่ หรือไม่สามารถใช้การชี้นำได้ OpenClaw จะรอจนกว่าการรันที่ทำงานอยู่จะสิ้นสุดก่อนเริ่มพรอมต์followup: ไม่ชี้นำ แต่เข้าคิวแต่ละข้อความสำหรับเทิร์นของเอเจนต์ในภายหลัง หลังจากการรันปัจจุบันสิ้นสุดcollect: ไม่ชี้นำ แต่รวมข้อความที่เข้าคิวเป็นเทิร์นติดตามผล รายการเดียว หลังจากช่วงเงียบ หากข้อความมีเป้าหมายเป็นช่องทาง/เธรดต่างกัน ระบบจะระบายแต่ละรายการแยกกันเพื่อคงการกำหนดเส้นทางinterrupt: ยกเลิกการรันที่ทำงานอยู่สำหรับเซสชันนั้น แล้วเรียกใช้ข้อความล่าสุด
สำหรับเวลาและพฤติกรรมของการขึ้นต่อกันที่เฉพาะเจาะจงกับรันไทม์ โปรดดู คิวการชี้นำ สำหรับคำสั่ง /steer <message> โดยตรง โปรดดู ชี้นำ
กำหนดค่าแบบส่วนกลางหรือต่อช่องทางผ่าน messages.queue:
{ 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และdcap: จำนวนข้อความในคิวสูงสุดต่อเซสชัน ค่าที่ต่ำกว่า1จะถูกละเว้นdrop: "summarize"(ค่าเริ่มต้น): ทิ้งรายการเก่าสุดในคิวตามความจำเป็น เก็บข้อมูลสรุปแบบกระชับ และแทรกข้อมูลเหล่านั้นเป็นพรอมต์ติดตามผลสังเคราะห์drop: "old": ทิ้งรายการเก่าสุดในคิวตามความจำเป็น โดยไม่เก็บข้อมูลสรุปdrop: "new": ปฏิเสธข้อความล่าสุดเมื่อคิวเต็มแล้ว
ค่าเริ่มต้น: debounceMs: 500, cap: 20, drop: summarize
การชี้นำและการสตรีม
เมื่อการสตรีมของช่องทางเป็น partial หรือ block การชี้นำอาจปรากฏเป็นการตอบกลับสั้น ๆ ที่มองเห็นได้หลายครั้ง ขณะที่การรันที่ทำงานอยู่ไปถึงขอบเขตของรันไทม์:
partial: ตัวอย่างแสดงผลอาจสิ้นสุดก่อนกำหนด แล้วตัวอย่างแสดงผลใหม่จะเริ่มหลังจากระบบยอมรับการชี้นำblock: บล็อกขนาดเท่าฉบับร่างอาจทำให้เกิดลักษณะเรียงต่อกันแบบเดียวกัน- หากไม่มีการสตรีม การชี้นำจะเปลี่ยนไปใช้การติดตามผลหลังจากการรันที่ทำงานอยู่ เมื่อรันไทม์ไม่สามารถรับการชี้นำภายในเทิร์นเดียวกันได้
steer จะไม่ยกเลิกเครื่องมือที่กำลังทำงานอยู่ ใช้ /queue interrupt เมื่อข้อความล่าสุดควรยกเลิกการรันปัจจุบัน
ลำดับความสำคัญ
สำหรับการเลือกโหมด OpenClaw จะพิจารณาตามลำดับดังนี้:
- การแทนค่าด้วย
/queueแบบอินไลน์หรือที่จัดเก็บไว้สำหรับแต่ละเซสชัน messages.queue.byChannel.<channel>messages.queue.mode- ค่าเริ่มต้น
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 โดยไม่ขึ้นกับการเพิ่มช่วงห่างดังกล่าว
- งานที่ทำงานอยู่และมีความคืบหน้าเมื่อไม่นานมานี้จะถูกบันทึกเป็น