Messages and delivery
คิวคำสั่ง
OpenClaw จัดลำดับการรันตอบกลับอัตโนมัติขาเข้า (ทุกช่องทาง) ผ่านคิวขนาดเล็กภายในโปรเซส เพื่อป้องกันไม่ให้การรันเอเจนต์หลายรายการชนกัน ขณะเดียวกันยังคงอนุญาตให้ทำงานแบบขนานระหว่างเซสชันได้อย่างปลอดภัย
เหตุผล
- การรันตอบกลับอัตโนมัติอาจใช้ทรัพยากรมาก (การเรียก LLM) และอาจชนกันเมื่อมีข้อความขาเข้าหลายข้อความมาถึงในช่วงเวลาใกล้กัน
- การจัดลำดับช่วยหลีกเลี่ยงการแย่งใช้ทรัพยากรร่วมกัน (ไฟล์เซสชัน บันทึก และ stdin ของ CLI) และลดโอกาสที่จะถึงขีดจำกัดอัตราของระบบต้นทาง
วิธีการทำงาน
- คิว FIFO ที่รับรู้เลนจะระบายแต่ละเลนตามขีดจำกัดการทำงานพร้อมกันที่กำหนดค่าได้ (ค่าเริ่มต้นคือ 1 สำหรับเลนที่ไม่ได้กำหนดค่า ส่วน
mainมีค่าเริ่มต้นเป็น 4 และsubagentเป็น 8) runEmbeddedAgentเข้าคิวตาม คีย์เซสชัน (เลนsession:<key>) เพื่อรับประกันว่าจะมีการรันที่ทำงานอยู่เพียงหนึ่งรายการต่อเซสชัน- จากนั้นการรันของแต่ละเซสชันจะถูกเพิ่มลงใน เลนส่วนกลาง (ค่าเริ่มต้นคือ
main) เพื่อจำกัดการทำงานแบบขนานโดยรวมตามagents.defaults.maxConcurrent - เมื่อเปิดใช้งานการบันทึกแบบละเอียด การรันที่เข้าคิวจะแสดงข้อความแจ้งสั้นๆ หากรอนานกว่า ~2s ก่อนเริ่มทำงาน
- ตัวบ่งชี้การพิมพ์ยังคงทำงานทันทีเมื่อเข้าคิว (หากช่องทางรองรับ) ดังนั้นประสบการณ์ของผู้ใช้จึงไม่เปลี่ยนแปลงระหว่างที่การรันรอถึงลำดับของตน
ค่าเริ่มต้น
เมื่อไม่ได้ตั้งค่า พื้นผิวช่องทางขาเข้าทั้งหมดจะใช้:
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จะล้างการแทนที่ของเซสชัน
การยกเลิกเทิร์นที่เข้าคิว
ขณะที่พรอมต์อยู่ในคิวติดตามผล/รวบรวม (ตัวอย่างเช่น chat.send จาก TUI หรือ
เว็บแชตที่มาถึงขณะที่อีกเทิร์นหนึ่งกำลังทำงาน) Gateway จะเก็บ
ข้อมูลประจำตัวสำหรับการยกเลิกที่ Gateway เป็นเจ้าของ สำหรับ runId ของไคลเอนต์นั้นไว้จนกว่าเนื้อหาที่เข้าคิว
จะทำงานหรือถูกทิ้ง ข้อมูลประจำตัวนี้จะติดตามเนื้อหาที่ถูกรวมเข้าใน
สรุปเมื่อเกินขีดจำกัด
chat.abortที่ระบุrunIdจะยกเลิกเทิร์นนั้นขณะที่ยัง อยู่ในคิว หากผู้ร้องขอได้รับอนุญาต (ใช้กฎความเป็นเจ้าของเดียวกับการรันที่ทำงานอยู่)chat.abortสำหรับเซสชันที่ไม่มีrunIdจะยกเลิก เทิร์นที่เข้าคิวซึ่งได้รับอนุญาต ก่อน แล้วจึงยกเลิกการรันที่ทำงานอยู่ซึ่งได้รับอนุญาต ลำดับนี้ป้องกันไม่ให้การระบายคิว เลื่อนงานเข้าสู่เซสชันที่หยุดเพียงบางส่วน- การล้างคิวทั้งเซสชันโดยไม่ตรวจสอบผู้ร้องขอแต่ละรายไม่ใช่ เส้นทางการหยุดสำหรับเซสชันที่มีเจ้าของหลายราย
- การรอในคิวจะไม่ถูกแสดงเป็นการรันเอเจนต์ที่ทำงานอยู่สำหรับ
sessions.listและ ไม่ได้เป็นเจ้าของความหมายด้านการหมดเวลาของการรันที่ทำงานอยู่ มีเพียงระยะที่ทำงานอยู่เท่านั้นที่เป็นเจ้าของ
ไคลเอนต์ที่ใช้ Gateway (รวมถึง openclaw tui) จะส่งต่อพรอมต์ระหว่างการรันและ
ให้ Gateway ใช้โหมดคิว Esc//stop ใช้การยกเลิกในขอบเขตเซสชัน
เพื่อไม่ให้การสูญเสียแฮนเดิลภายในเครื่องปล่อยให้พรอมต์ที่ยังอยู่ในคิวทำงานต่อไป
openclaw chat และ openclaw tui --local ใช้โหมดทั้งสี่แบบเดียวกันใน
รันไทม์แบบฝัง steer ภายในเครื่องจะแทรกเข้าในการรันแบบฝังที่ทำงานอยู่เมื่อ
รันไทม์นั้นรองรับการควบคุมทิศทาง มิฉะนั้นจะกลายเป็นรายการติดตามผล ส่วน followup และ
collect ยังคงเป็นงานภายในเครื่องที่รอดำเนินการ และ interrupt จะยกเลิกการรันภายในเครื่องที่ทำงานอยู่
ก่อนเริ่มข้อความใหม่ล่าสุด คำสั่ง /steer <message> โดยตรง
ไม่ใช่คำสั่งของโหมดภายในเครื่อง
ขอบเขตและการรับประกัน
- ใช้กับการรันเอเจนต์ตอบกลับอัตโนมัติในทุกช่องทางขาเข้าที่ใช้ไปป์ไลน์ตอบกลับของ Gateway (เว็บ WhatsApp, Telegram, Slack, Discord, Signal, iMessage, เว็บแชต เป็นต้น)
- เลนเริ่มต้น (
main) ใช้ทั่วทั้งโปรเซสสำหรับขาเข้าและ Heartbeat หลัก ตั้งค่าagents.defaults.maxConcurrentเพื่ออนุญาตให้หลายเซสชันทำงานแบบขนาน - อาจมีเลนเพิ่มเติม (เช่น
cron,cron-nested,nested,subagent) เพื่อให้งานเบื้องหลังทำงานแบบขนานได้โดยไม่ปิดกั้นการตอบกลับขาเข้า เทิร์นเอเจนต์ Cron แบบแยกจะครองสล็อตcronขณะที่การทำงานของเอเจนต์ภายในใช้cron-nestedโฟลว์nestedที่ใช้ร่วมกันและไม่ใช่ Cron จะรักษาพฤติกรรมเลนของตนเอง การรันที่แยกออกมาเหล่านี้จะถูกติดตามเป็น งานเบื้องหลัง - เลนต่อเซสชันรับประกันว่าจะมีการรันเอเจนต์เพียงหนึ่งรายการที่แตะเซสชันหนึ่งๆ ในแต่ละครั้ง
- ไม่มีการขึ้นต่อกันภายนอกหรือเธรดผู้ปฏิบัติงานเบื้องหลัง ใช้เพียง TypeScript และพรอมิส
การแก้ไขปัญหา
- หากคำสั่งดูเหมือนค้าง ให้เปิดใช้บันทึกแบบละเอียดและค้นหาบรรทัด "queued for ...ms" เพื่อยืนยันว่าคิวกำลังระบาย
- การรัน Codex app-server ที่ยอมรับเทิร์นแล้วหยุดส่งความคืบหน้าจะถูกอะแดปเตอร์ Codex ขัดจังหวะ เพื่อให้เลนเซสชันที่ทำงานอยู่ถูกปล่อยแทนที่จะรอจนการรันภายนอกหมดเวลา
- เมื่อเปิดใช้การวินิจฉัย เซสชันที่ยังคงอยู่ใน
processingเกินเกณฑ์การเตือนในตัวโดยไม่พบการตอบกลับ เครื่องมือ สถานะ บล็อก หรือความคืบหน้าของ ACP จะถูกจำแนกตามกิจกรรมปัจจุบัน:- งานที่ทำงานอยู่และมีความคืบหน้าเมื่อไม่นานมานี้จะบันทึกเป็น
session.long_runningการเรียกโมเดลแบบเงียบที่มีเจ้าของจะยังคงเป็นsession.long_runningจนถึงเกณฑ์การยกเลิกในตัวเช่นกัน เพื่อไม่ให้รายงานผู้ให้บริการที่ช้าหรือไม่สตรีมว่าหยุดชะงักเร็วเกินไป - งานที่ทำงานอยู่แต่ไม่มีความคืบหน้าเมื่อไม่นานมานี้จะบันทึกเป็น
session.stalledส่วนการเรียกโมเดลที่มีเจ้าของ การเรียกเครื่องมือที่ถูกปิดกั้น และการรันแบบฝังที่หยุดชะงักจะเปลี่ยนเป็นsession.stalledเมื่อถึงหรือเกินเกณฑ์การยกเลิก กิจกรรมโมเดล/เครื่องมือเก่าที่ไม่มีเจ้าของจะไม่ถูกซ่อนในฐานะงานที่ทำงานเป็นเวลานาน session.stuckสงวนไว้สำหรับข้อมูลบันทึกสถานะเซสชันเก่าที่กู้คืนได้ รวมถึงเซสชันที่เข้าคิวแต่ไม่ได้ทำงานซึ่งมีกิจกรรมโมเดล/เครื่องมือเก่าที่ไม่มีเจ้าของsession.stuckจะทริกเกอร์การกู้คืนที่สามารถปล่อยเลนเซสชันที่ได้รับผลกระทบเสมอ การจำแนกเป็นsession.stalledหลังเกินเกณฑ์การยกเลิก (การเรียกเครื่องมือที่ถูกปิดกั้น การเรียกโมเดลที่หยุดชะงัก หรือการรันแบบฝังที่หยุดชะงัก) ยังสามารถทริกเกอร์การกู้คืนด้วยการยกเลิกงานที่ทำงานอยู่ได้ ดังนั้นการจำแนกทั้งสองประเภทจึงสามารถแก้คิวที่ค้างได้ ไม่ใช่เฉพาะsession.stuck- บรรทัดบันทึกคำเตือน
session.stuckและsession.long_runningที่เกิดซ้ำจะเพิ่มช่วงหน่วงแบบเอ็กซ์โพเนนเชียลตราบใดที่เซสชันยังไม่เปลี่ยนแปลง อย่างไรก็ตาม ความพยายามกู้คืนยังคงทำงานในทุกจังหวะ Heartbeat โดยไม่ขึ้นกับช่วงหน่วงดังกล่าว
- งานที่ทำงานอยู่และมีความคืบหน้าเมื่อไม่นานมานี้จะบันทึกเป็น