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 web, 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 ทำงาน โดยไม่คำนึงถึงการหน่วงดังกล่าว
- งานที่ทำงานอยู่และมีความคืบหน้าล่าสุดจะบันทึกเป็น