Sessions and memory
การรับรู้สถานะเซสชัน
เมื่อหลายเซสชันทำงานกับปัญหาเดียวกัน ไม่ว่าจะเป็นผู้จัดการที่มอบหมายงานให้เซสชันลูก มนุษย์ที่เข้าไปยังเซสชันผู้ปฏิบัติงานโดยตรง หรือเอเจนต์สองตัวที่ประสานงานกันผ่าน sessions_send แต่ละเซสชันจะสร้างข้อสันนิษฐานเกี่ยวกับเซสชันอื่น ข้อสันนิษฐานเหล่านั้นจะล้าสมัยทันทีที่ผู้ดำเนินการรายอื่นเข้ามาแทรกแซง การรับรู้สถานะของเซสชันคือกลไกที่ตรวจพบการแทรกแซง แจ้งเซสชันที่ได้รับผลกระทบหนึ่งครั้ง และเปิดทางให้เซสชันนั้นตามข้อมูลให้ทันได้อย่างประหยัดก่อนดำเนินการ
องค์ประกอบสามส่วนทำงานร่วมกัน:
- บันทึกสัญญาณแบบคงทน บันทึกการเปลี่ยนแปลงสถานะที่เลือกไว้แยกตามเซสชัน
- ตัวเฝ้าดู เก็บเคอร์เซอร์แยกตามเป้าหมายและรับการแจ้งเตือนสถานะล้าสมัยแบบรวมเพียงหนึ่งครั้ง
- การปรับสถานะให้สอดคล้อง ดึงเฉพาะส่วนต่างที่แน่นอนผ่าน
session_statusโดยใช้changesSince
บันทึกสัญญาณ
OpenClaw เพิ่มเหตุการณ์ที่มีชนิดกำกับลงในฐานข้อมูลสถานะที่ใช้ร่วมกัน (session_state_events) เมื่อเซสชันที่ถูกเฝ้าดูมีการเปลี่ยนแปลงอย่างมีนัยสำคัญ เหตุการณ์ประกอบด้วยข้อมูลเมตาและข้อมูลสรุปหนึ่งบรรทัด โดยไม่มีเนื้อหาข้อความรวมอยู่ด้วยเด็ดขาด
| ชนิด | บันทึกเมื่อ | แจ้งตัวเฝ้าดู |
|---|---|---|
human_direct_message |
มนุษย์ส่งรอบสนทนาโดยตรงไปยังเซสชันที่ถูกเฝ้าดู | ใช่ |
upstream_missing |
แหล่งต้นทางของเซสชันที่รับเข้ามาหายไป | ใช่ |
goal_changed |
สถานะเป้าหมายของเซสชันถูกสร้าง อัปเดต หรือล้าง | ใช่ |
child_spawned |
มีการสร้างเซสชันลูกของเอเจนต์ย่อยหรือ ACP | ไม่ (ตั้งค่าเริ่มต้นให้เคอร์เซอร์) |
run_completed |
การเรียกใช้เซสชันลูกสิ้นสุดโดยสำเร็จ | ไม่ (บันทึกเท่านั้น) |
run_failed |
การเรียกใช้เซสชันลูกล้มเหลว หมดเวลา หรือถูกยกเลิก | ไม่ (บันทึกเท่านั้น) |
compacted |
ประวัติของเซสชันถูกย่อ | ไม่ (บันทึกเท่านั้น) |
adopted |
เซสชันแค็ตตาล็อกถูกรับเข้ามาใน OpenClaw | ไม่ (บันทึกเท่านั้น) |
แต่ละเหตุการณ์ระบุผู้ดำเนินการ (human, agent หรือ system) การเรียกใช้เซสชันลูกที่ถูกยกเลิกและหมดเวลาจะถูกบันทึกเป็นความล้มเหลว โดยคงผลลัพธ์ที่แน่นอน (cancelled, timeout หรือ error) ไว้ในเพย์โหลดของเหตุการณ์
เวอร์ชันสถานะ ของเซสชันคือหมายเลขลำดับสูงสุดในบันทึกของเซสชันนั้น โดยติดตามไว้ในส่วนหัวแบบคงทนประจำเซสชันซึ่งยังคงอยู่หลังการตัดทอน แถว sessions_list จะมี stateVersion เมื่อเซสชันบันทึกการเปลี่ยนแปลงแล้ว ส่วน session_status จะรายงานค่านี้เสมอ
ชนิดที่ใช้บันทึกเท่านั้นมีไว้สำหรับประวัติการปรับสถานะให้สอดคล้อง ไม่ใช่การแจ้งเตือน การส่งการแจ้งเตือนตามปกติเมื่อการเรียกใช้เซสชันลูกเสร็จสมบูรณ์ยังคงเป็นหน้าที่ของ การประกาศจากเอเจนต์ย่อย และบันทึกสัญญาณจะไม่สร้างรายการซ้ำ
ตัวเฝ้าดู
ตัวเฝ้าดูคือเซสชันที่เก็บเคอร์เซอร์ (session_watch_cursors) ของเป้าหมาย เคอร์เซอร์มาจากสองแหล่ง:
- โดยนัย (ขอบเขตการสร้างเซสชัน) เมื่อเซสชันสร้างเอเจนต์ย่อยหรือเซสชันลูกของ ACP เคอร์เซอร์ของเซสชันแม่จะได้รับค่าเริ่มต้นโดยอัตโนมัติเป็นเวอร์ชันขณะสร้างเซสชันลูก เซสชันแม่ไม่ต้องสมัครรับข้อมูลด้วยตนเอง
- โดยชัดแจ้ง (
sessions_send watch: true) ผู้ประสานงานใดๆ สามารถเฝ้าดูเป้าหมายที่ไม่ได้สร้างขึ้นจากตนเองได้ โดยส่งwatch: trueให้กับsessions_sendและหลังจากส่งข้อความสำเร็จ ผู้ส่งจะได้รับการลงทะเบียนเป็นตัวเฝ้าดูเซสชันที่ได้รับข้อความจริง การลงทะเบียนเริ่มต้นที่เวอร์ชันสถานะปัจจุบันของเป้าหมาย ประวัติก่อนหน้านั้นจะไม่ก่อให้เกิดการแจ้งเตือน ผลลัพธ์ของเครื่องมือจะรายงานwatched: true|falseเมื่อตั้งค่าพารามิเตอร์นี้
ข้อมูลประจำตัวของตัวเฝ้าดูต้องเป็นคีย์เซสชันที่ระบุเอเจนต์ ภายใต้ session.scope="global" คีย์ global ที่ใช้ร่วมกันมีความกำกวมระหว่างเอเจนต์ ดังนั้นเซสชันดังกล่าวจะมีบันทึกแบบคงทนและ changesSince แต่ไม่มีการแจ้งเตือนเชิงรุก
การเฝ้าดูจะล้างตัวเอง แถวเคอร์เซอร์จะหมดอายุตามระยะเวลาเก็บรักษาบันทึกสัญญาณ ถูกนำออกเมื่อเซสชันตัวเฝ้าดูรีเซ็ต และถูกลบเมื่อเซสชันฝ่ายใดฝ่ายหนึ่งถูกลบ ไม่มีคำสั่งยกเลิกการเฝ้าดูใน v1
เซสชันที่ถูกเฝ้าดูซึ่งรับมาจากแค็ตตาล็อกเซสชันจะได้รับการตรวจสอบกิจกรรมโดยตรงจากมนุษย์ในแหล่งต้นทางตามรอบเวลาคงที่ กิจกรรมที่ตรวจพบจะเข้าสู่บันทึกสัญญาณและกระบวนการของตัวเฝ้าดูเช่นเดียวกับรอบสนทนาโดยตรงอื่นๆ จากมนุษย์
หากแหล่งต้นทางของเซสชันที่รับเข้ามาถูกลบจากภายนอก การตรวจสอบว่าไม่พบติดต่อกันสามครั้ง (ประมาณสามรอบการตรวจสอบ) จะสร้างสัญญาณ upstream_missing หนึ่งครั้งให้ตัวเฝ้าดูและนำลิงก์ต้นทางออก เมื่อดำเนินเซสชันแค็ตตาล็อกต่ออีกครั้ง ระบบจะสร้างลิงก์ใหม่
การแจ้งเตือน: หนึ่งครั้ง ไม่ใช่หลายครั้ง
เมื่อเกิดเหตุการณ์ที่เข้าเกณฑ์การแจ้งเตือนและเคอร์เซอร์ของตัวเฝ้าดูล้าหลัง ตัวเฝ้าดูจะได้รับการแจ้งเตือนจากระบบหนึ่งครั้งในรอบสนทนาถัดไป:
เซสชัน "agent:main:subagent:child" มีการเปลี่ยนแปลง (ผู้ดำเนินการรายอื่น) ปรับสถานะให้สอดคล้องก่อนดำเนินการ: session_status sessionKey "agent:main:subagent:child" changesSince 12ตัวเฝ้าดูที่เป็นเซสชันหลักจะถูกปลุกทันทีผ่านการปลุกด้วย Heartbeat ส่วนตัวเฝ้าดูที่เป็นเอเจนต์ย่อยซ้อนกันจะได้รับการแจ้งเตือนในรอบสนทนาถัดไป
โปรโตคอลนี้ออกแบบมาเพื่อป้องกันสแปมโดยเจตนา:
- การแจ้งเตือนที่รอดำเนินการหนึ่งรายการต่อคู่ตัวเฝ้าดู/เป้าหมาย ข้อความแจ้งเตือนจะคงค่าแบบไบต์ต่อไบต์ขณะรอดำเนินการ และคิวเหตุการณ์ระบบจะกำจัดรายการซ้ำตามข้อความนั้น ดังนั้นแม้เป้าหมายเดียวกันจะเปลี่ยนแปลงอย่างรวดเร็วถึงยี่สิบครั้ง ก็ยังสร้างเพียงหนึ่งบรรทัดในพรอมต์ของตัวเฝ้าดู
- วอเตอร์มาร์กที่ตรึงไว้ เคอร์เซอร์จะตรึงตำแหน่งที่แจ้งเตือนเมื่อการแจ้งเตือนถูกเพิ่มลงในคิว เหตุการณ์สำคัญที่เกิดขึ้นต่อจากนั้นจะเลื่อนเฉพาะวอเตอร์มาร์กของเหตุการณ์สำคัญ โดยไม่แจ้งเตือนซ้ำ
- รับทราบเมื่อดึงออกจากคิว และเปิดใหม่เฉพาะเมื่อมีงานแทรกเข้ามา เมื่อรอบสนทนาของตัวเฝ้าดูใช้การแจ้งเตือนแล้ว เคอร์เซอร์จะเลื่อนไปข้างหน้า หากมีเหตุการณ์สำคัญเพิ่มเติมเกิดขึ้นระหว่างการเพิ่มลงในคิวและการดึงออกจากคิว ระบบจะเปิดการแจ้งเตือนใหม่เพียงหนึ่งรายการสำหรับส่วนที่เหลือ
- ระงับการแจ้งเตือนตนเอง ตัวเฝ้าดูจะไม่ได้รับการแจ้งเตือนเกี่ยวกับเหตุการณ์ที่ตนเองเป็นผู้ก่อ
- การกู้คืนหลังรีสตาร์ต การแจ้งเตือนที่รอดำเนินการอยู่ในคิวในหน่วยความจำ การกวาดตรวจเมื่อเริ่มต้นระบบจะสร้างการแจ้งเตือนเหล่านั้นขึ้นใหม่จากเคอร์เซอร์แบบคงทนหลัง Gateway รีสตาร์ต
การปรับสถานะให้สอดคล้อง
การแจ้งเตือนระบุสิ่งที่ตัวเฝ้าดูต้องทำอย่างชัดเจน session_status พร้อม changesSince: <version> จะส่งคืนเหตุการณ์ที่มีชนิดกำกับหลังจากเวอร์ชันนั้น (สูงสุด 200 รายการ) โดยไม่เลื่อนเคอร์เซอร์ใดๆ:
{ "stateVersion": 19, "stateChanges": { "events": [ { "sequence": 14, "kind": "human_direct_message", "actorType": "human", "summary": "ข้อความจากมนุษย์ผ่าน Telegram" }, { "sequence": 19, "kind": "goal_changed", "actorType": "human", "summary": "อัปเดตเป้าหมายแล้ว" } ], "historyGap": false }}historyGap: true หมายความว่าเวอร์ชันที่ร้องขออยู่ก่อนประวัติที่ยังเก็บรักษาไว้ ให้รีเฟรชสถานะทั้งหมดของเซสชัน (sessions_history, session_status) แทนการถือว่าการตอบกลับเป็นส่วนต่างที่แน่นอน สัญญาณช่องว่างนี้แม่นยำ เพราะมาจากวอเตอร์มาร์กที่ถูกตัดทอนประจำเซสชัน ไม่ได้อนุมานจากการคำนวณเลขลำดับ
พื้นที่จัดเก็บและขีดจำกัด
ประวัติอยู่ในฐานข้อมูลสถานะที่ใช้ร่วมกัน โดยจำกัดไว้ที่ 30 วันและ 50,000 แถว ส่วนหัวประจำเซสชันยังคงเพิ่มขึ้นทางเดียวหลังการตัดทอน การบันทึกเป็นแบบพยายามให้ดีที่สุด การเพิ่มข้อมูลที่ล้มเหลวจะถูกบันทึกไว้และจะไม่ทำให้รอบสนทนาต้นทางล้มเหลว ดังนั้น stateVersion จึงเป็นส่วนหัวของบันทึกสัญญาณ ไม่ใช่เวอร์ชันการบันทึกข้อมูลการเปลี่ยนแปลงแบบทรานแซกชัน
ขีดจำกัดปัจจุบัน:
- การส่งการแจ้งเตือนถือว่ามีกระบวนการ Gateway หนึ่งกระบวนการเป็นเจ้าของฐานข้อมูลสถานะที่ใช้ร่วมกัน Gateway หลายตัวใช้บันทึกแบบคงทนและ
changesSinceร่วมกันได้ แต่ v1 จะไม่ส่งการแจ้งเตือนข้ามกระบวนการ - เหตุการณ์ Compaction ครอบคลุมเจ้าของ Compaction ของรันไทม์แบบฝัง แต่ Compaction ที่เกิดขึ้นเฉพาะในเนทีฟฮาร์เนสยังไม่ได้รับการบันทึกอย่างครบถ้วน
- รายละเอียดเพย์โหลดของผลลัพธ์ที่ถูกยกเลิกในปัจจุบันสร้างโดยการเรียกใช้เซสชันลูกของ ACP ส่วนการยกเลิกเอเจนต์ย่อยแบบเนทีฟจะแสดงเป็นความล้มเหลวทั่วไป
- การตรวจจับเสียงสะท้อนจากตนเองในแหล่งต้นทางจะเปรียบเทียบข้อความผู้ใช้ที่ปรับรูปแบบแล้ว พรอมต์ภายนอกที่ตรงกับหนึ่งใน 10 ข้อความล่าสุดจากผู้ใช้ฝั่ง OpenClaw ของเซสชันจะถือว่าเป็นเสียงสะท้อนจากตนเอง
- แถว JSONL ภายในเครื่องของ Claude เพียงแถวเดียวที่มีขนาดใหญ่กว่าขีดจำกัดการสแกน 1 MiB ต่อรอบ จะขัดขวางเคอร์เซอร์ของเซสชันนั้นใน v1 ระบบจะไม่ข้ามไบต์ที่ยังไม่ได้จำแนกเด็ดขาด
- การตรวจสอบ Claude บน Node ที่จับคู่กันจะจำแนกรายการทรานสคริปต์ล่าสุด 50 รายการต่อรอบ ข้อมูลจำนวนมากกว่านี้อาจอยู่นอกหน้าต่างการสแกนของ v1
- การอ่านประวัติ Claude บน Node ที่จับคู่กันจะไม่แสดงผลลัพธ์ที่ยืนยันได้ว่าไม่พบเธรด ดังนั้นการลบ Claude ระยะไกลจึงไม่ถูกจำแนกเป็น
upstream_missingใน v1 - เซสชันแค็ตตาล็อกที่ยังไม่ได้รับเข้ามาจะยังคงอยู่นอกชั้นการรับรู้ใน v1
- เซสชันที่รับเข้ามาก่อนมีฟีเจอร์นี้จะไม่มีลิงก์ต้นทาง ให้ดำเนินเซสชันเหล่านั้นต่อจากแค็ตตาล็อกหนึ่งครั้งเพื่อเริ่มการตรวจสอบต้นทาง
- ลิงก์ต้นทางถือว่าคีย์ของแต่ละเซสชันที่รับเข้ามาจับคู่กับเอเจนต์เจ้าของเพียงหนึ่งตัว (การรับเข้ามาใช้เอเจนต์ของพื้นที่จัดเก็บเริ่มต้น) v1 จะไม่ตรวจสอบการรับเธรดภายนอกเดียวกันเข้ามาโดยเอเจนต์หลายตัว
ที่เกี่ยวข้อง
- เครื่องมือเซสชัน —
sessions_send,session_status,sessions_list - เอเจนต์ย่อย — ขอบเขตการสร้างเซสชันและการประกาศเมื่อเสร็จสมบูรณ์
- Heartbeat — วิธีที่การแจ้งเตือนในคิวปลุกเซสชันหลัก
- การจัดการเซสชัน — คีย์เซสชัน ขอบเขต และวงจรชีวิต