---
read_when:
    - คุณจำเป็นต้องดีบักรหัสเซสชัน, ไฟล์ JSONL ของทรานสคริปต์, หรือฟิลด์ของ sessions.json
    - คุณกำลังเปลี่ยนพฤติกรรม Compaction อัตโนมัติ หรือเพิ่มงานดูแลความเรียบร้อย “ก่อน Compaction”
    - คุณต้องการนำการล้างหน่วยความจำหรือรอบระบบแบบเงียบไปใช้
summary: 'เจาะลึก: ที่จัดเก็บเซสชัน + บันทึกทรานสคริปต์ วงจรชีวิต และกลไกภายในของ Compaction (อัตโนมัติ)'
title: เจาะลึกการจัดการเซสชัน
x-i18n:
    generated_at: "2026-05-02T20:59:25Z"
    model: gpt-5.5
    provider: openai
    source_hash: 8271d7b0786e1c47a8cec6e7bd73c3c86a433d629e17937fdd87fa756ed78d73
    source_path: reference/session-management-compaction.md
    workflow: 16
---

OpenClaw จัดการเซสชันตั้งแต่ต้นจนจบในพื้นที่เหล่านี้:

- **การกำหนดเส้นทางเซสชัน** (วิธีที่ข้อความขาเข้าถูกแมปไปยัง `sessionKey`)
- **ที่เก็บเซสชัน** (`sessions.json`) และสิ่งที่ติดตาม
- **การคงอยู่ของทรานสคริปต์** (`*.jsonl`) และโครงสร้างของไฟล์
- **สุขอนามัยของทรานสคริปต์** (การแก้ไขเฉพาะผู้ให้บริการก่อนการรัน)
- **ขีดจำกัดบริบท** (หน้าต่างบริบทเทียบกับโทเค็นที่ติดตาม)
- **Compaction** (การ compaction แบบกำหนดเองและอัตโนมัติ) และตำแหน่งสำหรับ hook งานก่อน compaction
- **งานดูแลเบื้องหลังแบบเงียบ** (การเขียนหน่วยความจำที่ไม่ควรสร้างเอาต์พุตที่ผู้ใช้มองเห็นได้)

หากต้องการภาพรวมระดับสูงก่อน ให้เริ่มจาก:

- [การจัดการเซสชัน](/th/concepts/session)
- [Compaction](/th/concepts/compaction)
- [ภาพรวมหน่วยความจำ](/th/concepts/memory)
- [การค้นหาหน่วยความจำ](/th/concepts/memory-search)
- [การตัดเซสชัน](/th/concepts/session-pruning)
- [สุขอนามัยของทรานสคริปต์](/th/reference/transcript-hygiene)

---

## แหล่งข้อมูลจริง: Gateway

OpenClaw ออกแบบโดยมี **กระบวนการ Gateway** เดียวที่เป็นเจ้าของสถานะเซสชัน

- UI (แอป macOS, Control UI บนเว็บ, TUI) ควรสอบถาม Gateway สำหรับรายการเซสชันและจำนวนโทเค็น
- ในโหมดรีโมต ไฟล์เซสชันอยู่บนโฮสต์รีโมต การ “ตรวจไฟล์ใน Mac เครื่อง local ของคุณ” จะไม่สะท้อนสิ่งที่ Gateway ใช้อยู่

---

## สองชั้นการคงอยู่

OpenClaw คงอยู่เซสชันไว้ในสองชั้น:

1. **ที่เก็บเซสชัน (`sessions.json`)**
   - แมปคีย์/ค่า: `sessionKey -> SessionEntry`
   - ขนาดเล็ก เปลี่ยนแปลงได้ และแก้ไขได้อย่างปลอดภัย (หรือลบรายการได้)
   - ติดตามเมทาดาทาของเซสชัน (id เซสชันปัจจุบัน กิจกรรมล่าสุด toggle ตัวนับโทเค็น ฯลฯ)

2. **ทรานสคริปต์ (`<sessionId>.jsonl`)**
   - ทรานสคริปต์แบบผนวกท้ายเท่านั้นพร้อมโครงสร้างต้นไม้ (รายการมี `id` + `parentId`)
   - จัดเก็บบทสนทนาจริง + การเรียกเครื่องมือ + สรุป compaction
   - ใช้สร้างบริบทโมเดลใหม่สำหรับเทิร์นในอนาคต
   - ข้าม checkpoint ดีบักขนาดใหญ่ก่อน compaction เมื่อทรานสคริปต์ที่ใช้งานอยู่มีขนาดเกินเพดานขนาด checkpoint เพื่อหลีกเลี่ยงการคัดลอก `.checkpoint.*.jsonl` ขนาดใหญ่อีกชุดหนึ่ง

ตัวอ่านประวัติของ Gateway ควรหลีกเลี่ยงการ materialize ทรานสคริปต์ทั้งไฟล์ เว้นแต่ surface นั้นต้องการการเข้าถึงประวัติแบบกำหนดเองโดยชัดเจน ประวัติหน้าแรก ประวัติแชตแบบฝัง การกู้คืนหลังรีสตาร์ต และการตรวจโทเค็น/การใช้งานใช้การอ่านท้ายไฟล์แบบมีขอบเขต การสแกนทรานสคริปต์ทั้งไฟล์จะผ่านดัชนีทรานสคริปต์แบบ async ซึ่งแคชตามพาธไฟล์รวมกับ `mtimeMs`/`size` และแชร์ระหว่างตัวอ่านที่ทำงานพร้อมกัน

---

## ตำแหน่งบนดิสก์

ต่อ agent บนโฮสต์ Gateway:

- ที่เก็บ: `~/.openclaw/agents/<agentId>/sessions/sessions.json`
- ทรานสคริปต์: `~/.openclaw/agents/<agentId>/sessions/<sessionId>.jsonl`
  - เซสชันหัวข้อ Telegram: `.../<sessionId>-topic-<threadId>.jsonl`

OpenClaw resolve รายการเหล่านี้ผ่าน `src/config/sessions.ts`

---

## การบำรุงรักษาที่เก็บและการควบคุมดิสก์

การคงอยู่ของเซสชันมีการควบคุมการบำรุงรักษาอัตโนมัติ (`session.maintenance`) สำหรับ `sessions.json`, artifact ของทรานสคริปต์ และ sidecar ของ trajectory:

- `mode`: `warn` (ค่าเริ่มต้น) หรือ `enforce`
- `pruneAfter`: ขีดจำกัดอายุของรายการที่ค้าง (ค่าเริ่มต้น `30d`)
- `maxEntries`: เพดานจำนวนรายการใน `sessions.json` (ค่าเริ่มต้น `500`)
- `resetArchiveRetention`: ระยะเวลาเก็บรักษา archive ทรานสคริปต์ `*.reset.<timestamp>` (ค่าเริ่มต้น: เหมือนกับ `pruneAfter`; `false` ปิดการล้างข้อมูล)
- `maxDiskBytes`: งบประมาณไดเรกทอรีเซสชันแบบไม่บังคับ
- `highWaterBytes`: เป้าหมายแบบไม่บังคับหลังล้างข้อมูล (ค่าเริ่มต้น `80%` ของ `maxDiskBytes`)

การเขียน Gateway ปกติจะไหลผ่านตัวเขียนเซสชันรายที่เก็บ ซึ่ง serialize การเปลี่ยนแปลงในกระบวนการโดยไม่ใช้ file lock ตอนรันไทม์ ตัวช่วย patch ใน hot path จะยืมแคช mutable ที่ผ่านการตรวจสอบแล้วระหว่างถือ slot ของตัวเขียนนั้น ทำให้ไฟล์ `sessions.json` ขนาดใหญ่ไม่ถูก clone หรืออ่านซ้ำสำหรับทุกการอัปเดตเมทาดาทา โค้ดรันไทม์ควรใช้ `updateSessionStore(...)` หรือ `updateSessionStoreEntry(...)`; การบันทึกทั้งที่เก็บโดยตรงเป็นเครื่องมือความเข้ากันได้และการบำรุงรักษาแบบ offline เมื่อเข้าถึง Gateway ได้ คำสั่ง `openclaw sessions cleanup` และ `openclaw agents delete` ที่ไม่ใช่ dry run จะ delegate การเปลี่ยนแปลงที่เก็บไปยัง Gateway เพื่อให้การล้างข้อมูลเข้าคิวตัวเขียนเดียวกัน; `--store <path>` เป็นพาธซ่อมแซม offline โดยชัดเจนสำหรับการบำรุงรักษาไฟล์โดยตรง การล้างข้อมูล `maxEntries` ยังคงทำเป็น batch สำหรับเพดานขนาด production ดังนั้นที่เก็บอาจเกินเพดานที่กำหนดไว้ชั่วคราวก่อนการล้างข้อมูล high-water ครั้งถัดไปจะเขียนลดลงกลับมา การอ่านที่เก็บเซสชันจะไม่ prune หรือ cap รายการระหว่างการเริ่มต้น Gateway; ใช้การเขียนหรือ `openclaw sessions cleanup --enforce` สำหรับการล้างข้อมูล `openclaw sessions cleanup --enforce` ยังใช้เพดานที่กำหนดทันที

การบำรุงรักษาจะเก็บ pointer บทสนทนาภายนอกที่คงทน เช่น เซสชันกลุ่มและเซสชันแชตตาม thread แต่รายการรันไทม์สังเคราะห์สำหรับ cron, hook, heartbeat, ACP และ sub-agent ยังสามารถถูกลบได้เมื่อเกินอายุ จำนวน หรืองบประมาณดิสก์ที่กำหนด

OpenClaw ไม่สร้าง backup หมุนเวียน `sessions.json.bak.*` อัตโนมัติระหว่างการเขียน Gateway อีกต่อไป คีย์เดิม `session.maintenance.rotateBytes` จะถูกละเว้น และ `openclaw doctor --fix` จะลบคีย์นี้ออกจาก config เก่า

การเปลี่ยนแปลงทรานสคริปต์ใช้ write lock ของเซสชันบนไฟล์ทรานสคริปต์ การได้ lock จะรอนานสุด `session.writeLock.acquireTimeoutMs` ก่อนแสดงข้อผิดพลาดว่าเซสชันไม่ว่าง ค่าเริ่มต้นคือ `60000` ms เพิ่มค่านี้เฉพาะเมื่อมีงานเตรียม ล้างข้อมูล compaction หรือ mirror ทรานสคริปต์ที่ถูกต้องตามปกติแย่งใช้ lock นานกว่านั้นบนเครื่องที่ช้า การตรวจจับ lock ค้างและคำเตือนเวลาถือ lock สูงสุดยังคงเป็นนโยบายแยกกัน

ลำดับการบังคับใช้สำหรับการล้างข้อมูลงบประมาณดิสก์ (`mode: "enforce"`):

1. ลบ artifact ที่ archive ไว้เก่าที่สุด ทรานสคริปต์กำพร้า หรือ trajectory กำพร้าก่อน
2. หากยังเกินเป้าหมาย ให้ขับรายการเซสชันเก่าที่สุดและไฟล์ทรานสคริปต์/trajectory ของรายการนั้นออก
3. ดำเนินต่อจนกว่าการใช้งานจะอยู่ที่หรือต่ำกว่า `highWaterBytes`

ใน `mode: "warn"` OpenClaw จะรายงานการขับออกที่อาจเกิดขึ้น แต่ไม่เปลี่ยนแปลงที่เก็บ/ไฟล์

รันการบำรุงรักษาตามต้องการ:

```bash
openclaw sessions cleanup --dry-run
openclaw sessions cleanup --enforce
```

---

## เซสชัน Cron และ log การรัน

การรัน cron แบบแยกยังสร้างรายการเซสชัน/ทรานสคริปต์ด้วย และมีการควบคุมการเก็บรักษาเฉพาะ:

- `cron.sessionRetention` (ค่าเริ่มต้น `24h`) prune เซสชันการรัน cron แบบแยกเก่าออกจากที่เก็บเซสชัน (`false` ปิด)
- `cron.runLog.maxBytes` + `cron.runLog.keepLines` prune ไฟล์ `~/.openclaw/cron/runs/<jobId>.jsonl` (ค่าเริ่มต้น: `2_000_000` ไบต์และ `2000` บรรทัด)

เมื่อ cron บังคับสร้างเซสชันการรันแบบแยกใหม่ จะ sanitize รายการเซสชัน `cron:<jobId>` ก่อนหน้าก่อนเขียนแถวใหม่ โดยจะนำค่ากำหนดที่ปลอดภัย เช่น การตั้งค่า thinking/fast/verbose, label และการ override model/auth ที่ผู้ใช้เลือกอย่างชัดเจนติดไปด้วย และจะทิ้งบริบทบทสนทนาโดยรอบ เช่น การกำหนดเส้นทาง channel/group, นโยบายการส่งหรือคิว, elevation, origin และการ binding รันไทม์ ACP เพื่อให้การรันแบบแยกใหม่ไม่สามารถสืบทอดการส่งมอบหรืออำนาจรันไทม์ที่ค้างจากการรันเก่า

---

## คีย์เซสชัน (`sessionKey`)

`sessionKey` ระบุว่า _คุณอยู่ใน bucket บทสนทนาใด_ (การกำหนดเส้นทาง + การแยก)

รูปแบบทั่วไป:

- แชตหลัก/โดยตรง (ต่อ agent): `agent:<agentId>:<mainKey>` (ค่าเริ่มต้น `main`)
- กลุ่ม: `agent:<agentId>:<channel>:group:<id>`
- ห้อง/channel (Discord/Slack): `agent:<agentId>:<channel>:channel:<id>` หรือ `...:room:<id>`
- Cron: `cron:<job.id>`
- Webhook: `hook:<uuid>` (เว้นแต่ถูก override)

กฎ canonical มีเอกสารที่ [/concepts/session](/th/concepts/session)

---

## id เซสชัน (`sessionId`)

แต่ละ `sessionKey` ชี้ไปยัง `sessionId` ปัจจุบัน (ไฟล์ทรานสคริปต์ที่ดำเนินบทสนทนาต่อ)

หลักทั่วไป:

- **รีเซ็ต** (`/new`, `/reset`) สร้าง `sessionId` ใหม่สำหรับ `sessionKey` นั้น
- **รีเซ็ตรายวัน** (ค่าเริ่มต้น 4:00 น. ตามเวลาท้องถิ่นบนโฮสต์ gateway) สร้าง `sessionId` ใหม่เมื่อมีข้อความถัดไปหลังขอบเขตการรีเซ็ต
- **หมดอายุจากการว่าง** (`session.reset.idleMinutes` หรือ `session.idleMinutes` เดิม) สร้าง `sessionId` ใหม่เมื่อมีข้อความมาถึงหลังช่วงเวลาว่าง เมื่อกำหนดทั้งรายวัน + ว่างไว้ ตัวใดหมดอายุก่อนจะมีผล
- **เหตุการณ์ระบบ** (heartbeat, การปลุก cron, การแจ้งเตือน exec, งานบันทึกสถานะของ gateway) อาจเปลี่ยนแถวเซสชัน แต่ไม่ต่ออายุความสดใหม่ของการรีเซ็ตรายวัน/จากการว่าง การ rollover เมื่อรีเซ็ตจะทิ้งประกาศเหตุการณ์ระบบที่ค้างคิวไว้สำหรับเซสชันก่อนหน้า ก่อนสร้าง prompt ใหม่
- **นโยบาย parent fork** ใช้ branch ที่ใช้งานอยู่ของ PI เมื่อสร้าง thread หรือ fork ของ subagent หาก branch นั้นใหญ่เกินไป OpenClaw จะเริ่ม child ด้วยบริบทแยกแทนที่จะล้มเหลวหรือสืบทอดประวัติที่ใช้ไม่ได้ นโยบายการปรับขนาดเป็นอัตโนมัติ; config เดิม `session.parentForkMaxTokens` ถูกลบโดย `openclaw doctor --fix`

รายละเอียดการใช้งานจริง: การตัดสินใจเกิดใน `initSessionState()` ใน `src/auto-reply/reply/session.ts`

---

## schema ของที่เก็บเซสชัน (`sessions.json`)

ประเภทค่าของที่เก็บคือ `SessionEntry` ใน `src/config/sessions.ts`

ฟิลด์สำคัญ (ไม่ครบทั้งหมด):

- `sessionId`: id ทรานสคริปต์ปัจจุบัน (ชื่อไฟล์ derive จากค่านี้ เว้นแต่ตั้ง `sessionFile`)
- `sessionStartedAt`: timestamp เริ่มต้นสำหรับ `sessionId` ปัจจุบัน; ความสดใหม่ของการรีเซ็ตรายวันใช้ค่านี้ แถวเดิมอาจ derive จาก header เซสชัน JSONL
- `lastInteractionAt`: timestamp การโต้ตอบจริงล่าสุดของผู้ใช้/channel; ความสดใหม่ของการรีเซ็ตจากการว่างใช้ค่านี้ เพื่อให้ heartbeat, cron และเหตุการณ์ exec ไม่ทำให้เซสชันคงอยู่ แถวเดิมที่ไม่มีฟิลด์นี้จะ fallback ไปยังเวลาเริ่มต้นเซสชันที่กู้คืนได้สำหรับความสดใหม่จากการว่าง
- `updatedAt`: timestamp การเปลี่ยนแปลงแถวที่เก็บล่าสุด ใช้สำหรับการแสดงรายการ การ prune และงานบันทึกสถานะ ไม่ใช่อำนาจตัดสินความสดใหม่ของการรีเซ็ตรายวัน/จากการว่าง
- `sessionFile`: override พาธทรานสคริปต์แบบชัดเจนที่ไม่บังคับ
- `chatType`: `direct | group | room` (ช่วย UI และนโยบายการส่ง)
- `provider`, `subject`, `room`, `space`, `displayName`: เมทาดาทาสำหรับ label ของกลุ่ม/channel
- Toggle:
  - `thinkingLevel`, `verboseLevel`, `reasoningLevel`, `elevatedLevel`
  - `sendPolicy` (override ต่อเซสชัน)
- การเลือกโมเดล:
  - `providerOverride`, `modelOverride`, `authProfileOverride`
- ตัวนับโทเค็น (best-effort / ขึ้นกับผู้ให้บริการ):
  - `inputTokens`, `outputTokens`, `totalTokens`, `contextTokens`
- `compactionCount`: จำนวนครั้งที่ auto-compaction เสร็จสำหรับคีย์เซสชันนี้
- `memoryFlushAt`: timestamp สำหรับการ flush หน่วยความจำก่อน compaction ครั้งล่าสุด
- `memoryFlushCompactionCount`: จำนวน compaction เมื่อตอนการ flush ล่าสุดรัน

ที่เก็บนี้แก้ไขได้อย่างปลอดภัย แต่ Gateway คืออำนาจตัดสิน: มันอาจเขียนใหม่หรือ rehydrate รายการเมื่อเซสชันทำงาน

---

## โครงสร้างทรานสคริปต์ (`*.jsonl`)

ทรานสคริปต์จัดการโดย `SessionManager` ของ `@mariozechner/pi-coding-agent`

ไฟล์เป็น JSONL:

- บรรทัดแรก: header เซสชัน (`type: "session"` รวม `id`, `cwd`, `timestamp`, `parentSession` แบบไม่บังคับ)
- จากนั้น: รายการเซสชันที่มี `id` + `parentId` (ต้นไม้)

ประเภทรายการที่ควรรู้:

- `message`: ข้อความ user/assistant/toolResult
- `custom_message`: ข้อความที่ extension inject ซึ่ง _เข้า_ บริบทโมเดล (สามารถซ่อนจาก UI ได้)
- `custom`: สถานะ extension ที่ _ไม่เข้า_ บริบทโมเดล
- `compaction`: สรุป compaction ที่คงอยู่พร้อม `firstKeptEntryId` และ `tokensBefore`
- `branch_summary`: สรุปที่คงอยู่เมื่อนำทาง branch ของต้นไม้

OpenClaw ตั้งใจ **ไม่** “แก้ไข” ทรานสคริปต์; Gateway ใช้ `SessionManager` เพื่ออ่าน/เขียนไฟล์เหล่านั้น

---

## หน้าต่างบริบทเทียบกับโทเค็นที่ติดตาม

มีแนวคิดต่างกันสองอย่างที่สำคัญ:

1. **หน้าต่างบริบทของโมเดล**: เพดานแข็งต่อโมเดล (โทเค็นที่โมเดลเห็นได้)
2. **ตัวนับในที่เก็บเซสชัน**: สถิติแบบ rolling ที่เขียนลง `sessions.json` (ใช้สำหรับ /status และ dashboard)

หากคุณกำลังปรับขีดจำกัด:

- หน้าต่างบริบทมาจาก catalog โมเดล (และสามารถ override ผ่าน config ได้)
- `contextTokens` ในที่เก็บเป็นค่าประมาณ/ค่ารายงานตอนรันไทม์ อย่าถือว่าเป็นการรับประกันแบบเข้มงวด

ดูเพิ่มเติมที่ [/token-use](/th/reference/token-use)

---

## Compaction: คืออะไร

Compaction สรุปบทสนทนาเก่าเข้าเป็นรายการ `compaction` ที่คงอยู่ในทรานสคริปต์ และคงข้อความล่าสุดไว้ครบถ้วน

หลัง compaction เทิร์นในอนาคตจะเห็น:

- สรุป compaction
- ข้อความหลัง `firstKeptEntryId`

Compaction **คงอยู่ถาวร** (ต่างจากการตัดเซสชัน) ดู [/concepts/session-pruning](/th/concepts/session-pruning)

## ขอบเขตชังก์ Compaction และการจับคู่เครื่องมือ

เมื่อ OpenClaw แยกทรานสคริปต์ยาวออกเป็นชังก์ Compaction จะเก็บ
การเรียกเครื่องมือของผู้ช่วยให้จับคู่กับรายการ `toolResult` ที่ตรงกัน

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

---

## Auto-compaction เกิดขึ้นเมื่อใด (รันไทม์ Pi)

ในเอเจนต์ Pi แบบฝังตัว auto-compaction จะทริกเกอร์ในสองกรณี:

1. **การกู้คืนจากโอเวอร์โฟลว์**: โมเดลส่งคืนข้อผิดพลาดบริบทล้น
   (`request_too_large`, `context length exceeded`, `input exceeds the maximum
number of tokens`, `input token count exceeds the maximum number of input
tokens`, `input is too long for the model`, `ollama error: context length
exceeded` และตัวแปรที่มีรูปแบบคล้ายผู้ให้บริการ) → compact → ลองใหม่
2. **การดูแลรักษาตามเกณฑ์**: หลังจากเทิร์นสำเร็จ เมื่อ:

`contextTokens > contextWindow - reserveTokens`

โดยที่:

- `contextWindow` คือหน้าต่างบริบทของโมเดล
- `reserveTokens` คือพื้นที่เผื่อที่สงวนไว้สำหรับพรอมป์ + เอาต์พุตโมเดลถัดไป

นี่คือซีแมนติกของรันไทม์ Pi (OpenClaw ใช้เหตุการณ์เหล่านี้ แต่ Pi เป็นผู้ตัดสินใจว่าจะ compact เมื่อใด)

OpenClaw ยังสามารถทริกเกอร์ Compaction ภายในเครื่องแบบ preflight ก่อนเปิด
การรันถัดไปเมื่อมีการตั้งค่า `agents.defaults.compaction.maxActiveTranscriptBytes` และไฟล์
ทรานสคริปต์ที่ใช้งานถึงขนาดนั้น นี่คือการ์ดขนาดไฟล์สำหรับต้นทุนการเปิดใหม่ในเครื่อง
ไม่ใช่การเก็บถาวรแบบดิบ: OpenClaw ยังคงรัน Compaction เชิงความหมายตามปกติ
และต้องใช้ `truncateAfterCompaction` เพื่อให้สรุปที่ compact แล้วกลายเป็น
ทรานสคริปต์ตัวสืบทอดใหม่ได้

สำหรับการรัน Pi แบบฝังตัว `agents.defaults.compaction.midTurnPrecheck.enabled: true`
จะเพิ่มการ์ดลูปเครื่องมือแบบเลือกเปิดใช้ หลังจากเพิ่มผลลัพธ์เครื่องมือและก่อน
การเรียกโมเดลถัดไป OpenClaw จะประมาณแรงกดดันต่อพรอมป์โดยใช้ตรรกะงบประมาณ preflight
เดียวกับที่ใช้ตอนเริ่มเทิร์น หากบริบทไม่พอดีอีกต่อไป การ์ดจะ
ไม่ compact ภายในฮุก `transformContext` ของ Pi แต่จะส่งสัญญาณ precheck กลางเทิร์น
แบบมีโครงสร้าง หยุดการส่งพรอมป์ปัจจุบัน และปล่อยให้
ลูปการรันภายนอกใช้เส้นทางกู้คืนที่มีอยู่: ตัดทอนผลลัพธ์เครื่องมือที่ใหญ่เกินไป
เมื่อเพียงพอ หรือทริกเกอร์โหมด Compaction ที่กำหนดค่าไว้แล้วลองใหม่ ตัวเลือกนี้
ปิดไว้โดยค่าเริ่มต้นและทำงานกับโหมด Compaction ทั้ง `default` และ `safeguard`
รวมถึง Compaction แบบ safeguard ที่รองรับโดยผู้ให้บริการ
สิ่งนี้เป็นอิสระจาก `maxActiveTranscriptBytes`: การ์ดขนาดไบต์จะรัน
ก่อนเปิดเทิร์น ส่วน precheck กลางเทิร์นจะรันภายหลังในลูปเครื่องมือ Pi แบบฝังตัว
หลังจากมีการเพิ่มผลลัพธ์เครื่องมือใหม่แล้ว

---

## การตั้งค่า Compaction (`reserveTokens`, `keepRecentTokens`)

การตั้งค่า Compaction ของ Pi อยู่ในการตั้งค่า Pi:

```json5
{
  compaction: {
    enabled: true,
    reserveTokens: 16384,
    keepRecentTokens: 20000,
  },
}
```

OpenClaw ยังบังคับใช้ค่าขั้นต่ำด้านความปลอดภัยสำหรับการรันแบบฝังตัว:

- หาก `compaction.reserveTokens < reserveTokensFloor` OpenClaw จะเพิ่มค่าให้
- ค่าเริ่มต้นขั้นต่ำคือ `20000` โทเค็น
- ตั้งค่า `agents.defaults.compaction.reserveTokensFloor: 0` เพื่อปิดค่าขั้นต่ำ
- หากค่าสูงกว่าอยู่แล้ว OpenClaw จะปล่อยไว้ตามเดิม
- `/compact` แบบแมนนวลจะเคารพ `agents.defaults.compaction.keepRecentTokens`
  ที่กำหนดอย่างชัดเจน และคงจุดตัดส่วนท้ายล่าสุดของ Pi ไว้ หากไม่มีงบประมาณเก็บรักษา
  ที่กำหนดอย่างชัดเจน Compaction แบบแมนนวลจะยังคงเป็นเช็กพอยต์แบบแข็ง และบริบทที่สร้างใหม่จะเริ่มจาก
  สรุปใหม่
- ตั้งค่า `agents.defaults.compaction.midTurnPrecheck.enabled: true` เพื่อรัน
  precheck ลูปเครื่องมือแบบเลือกเปิดใช้หลังผลลัพธ์เครื่องมือใหม่และก่อนการเรียกโมเดล
  ถัดไป นี่เป็นเพียงทริกเกอร์เท่านั้น การสร้างสรุปยังคงใช้เส้นทาง
  Compaction ที่กำหนดค่าไว้ สิ่งนี้เป็นอิสระจาก `maxActiveTranscriptBytes` ซึ่งเป็น
  การ์ดขนาดไบต์ของทรานสคริปต์ที่ใช้งาน ณ จุดเริ่มเทิร์น
- ตั้งค่า `agents.defaults.compaction.maxActiveTranscriptBytes` เป็นค่าไบต์หรือ
  สตริง เช่น `"20mb"` เพื่อรัน Compaction ภายในเครื่องก่อนเทิร์นเมื่อทรานสคริปต์
  ที่ใช้งานมีขนาดใหญ่ การ์ดนี้ทำงานเฉพาะเมื่อ
  เปิดใช้ `truncateAfterCompaction` ด้วยเท่านั้น ปล่อยว่างไว้หรือตั้งเป็น `0` เพื่อ
  ปิด
- เมื่อเปิดใช้ `agents.defaults.compaction.truncateAfterCompaction`
  OpenClaw จะหมุนทรานสคริปต์ที่ใช้งานไปเป็น JSONL ตัวสืบทอดที่ compact แล้วหลัง
  Compaction ทรานสคริปต์เต็มเดิมจะยังคงถูกเก็บถาวรและเชื่อมโยงจาก
  เช็กพอยต์ Compaction แทนการเขียนทับในตำแหน่งเดิม

เหตุผล: เหลือพื้นที่เผื่อให้เพียงพอสำหรับ “งานดูแลระบบ” หลายเทิร์น (เช่น การเขียนหน่วยความจำ) ก่อนที่ Compaction จะกลายเป็นสิ่งที่หลีกเลี่ยงไม่ได้

การนำไปใช้: `ensurePiCompactionReserveTokens()` ใน `src/agents/pi-settings.ts`
(ถูกเรียกจาก `src/agents/pi-embedded-runner.ts`)

---

## ผู้ให้บริการ Compaction แบบเสียบได้

Plugins สามารถลงทะเบียนผู้ให้บริการ Compaction ผ่าน `registerCompactionProvider()` บน API ของ Plugin ได้ เมื่อ `agents.defaults.compaction.provider` ถูกตั้งค่าเป็น id ของผู้ให้บริการที่ลงทะเบียนไว้ ส่วนขยาย safeguard จะมอบหมายการสรุปให้ผู้ให้บริการนั้นแทนไปป์ไลน์ `summarizeInStages` ในตัว

- `provider`: id ของ Plugin ผู้ให้บริการ Compaction ที่ลงทะเบียนไว้ ปล่อยว่างไว้สำหรับการสรุปด้วย LLM เริ่มต้น
- การตั้งค่า `provider` จะบังคับ `mode: "safeguard"`
- ผู้ให้บริการจะได้รับคำสั่ง Compaction และนโยบายการคงตัวระบุเดียวกับเส้นทางในตัว
- safeguard ยังคงรักษาบริบท suffix ของเทิร์นล่าสุดและเทิร์นที่ถูกแบ่งหลังเอาต์พุตของผู้ให้บริการ
- การสรุป safeguard ในตัวจะกลั่นสรุปก่อนหน้าอีกครั้งพร้อมข้อความใหม่
  แทนการคงสรุปก่อนหน้าแบบเต็มไว้ตามตัวอักษร
- โหมด safeguard เปิดใช้การตรวจสอบคุณภาพสรุปโดยค่าเริ่มต้น ตั้งค่า
  `qualityGuard.enabled: false` เพื่อข้ามพฤติกรรมลองใหม่เมื่อเอาต์พุตมีรูปแบบผิด
- หากผู้ให้บริการล้มเหลวหรือส่งคืนผลลัพธ์ว่าง OpenClaw จะถอยกลับไปใช้การสรุปด้วย LLM ในตัวโดยอัตโนมัติ
- สัญญาณยกเลิก/หมดเวลาจะถูกโยนซ้ำ (ไม่ถูกกลืน) เพื่อเคารพการยกเลิกของผู้เรียก

แหล่งที่มา: `src/plugins/compaction-provider.ts`, `src/agents/pi-hooks/compaction-safeguard.ts`

---

## พื้นผิวที่ผู้ใช้มองเห็น

คุณสามารถสังเกต Compaction และสถานะเซสชันได้ผ่าน:

- `/status` (ในเซสชันแชตใดก็ได้)
- `openclaw status` (CLI)
- `openclaw sessions` / `sessions --json`
- โหมดละเอียด: `🧹 Auto-compaction complete` + จำนวน Compaction

---

## งานดูแลระบบแบบเงียบ (`NO_REPLY`)

OpenClaw รองรับเทิร์นแบบ “เงียบ” สำหรับงานเบื้องหลังที่ผู้ใช้ไม่ควรเห็นเอาต์พุตระหว่างทาง

ข้อตกลง:

- ผู้ช่วยเริ่มเอาต์พุตด้วยโทเค็นเงียบที่ตรงกันทุกตัวอักษร `NO_REPLY` /
  `no_reply` เพื่อบ่งชี้ว่า “อย่าส่งคำตอบให้ผู้ใช้”
- OpenClaw จะตัด/ระงับสิ่งนี้ในเลเยอร์การส่งมอบ
- การระงับโทเค็นเงียบแบบตรงตัวไม่คำนึงถึงตัวพิมพ์เล็กใหญ่ ดังนั้น `NO_REPLY` และ
  `no_reply` จะนับทั้งคู่เมื่อ payload ทั้งหมดเป็นเพียงโทเค็นเงียบ
- สิ่งนี้มีไว้สำหรับเทิร์นเบื้องหลัง/ไม่ส่งมอบจริงเท่านั้น ไม่ใช่ทางลัดสำหรับ
  คำขอผู้ใช้ที่ดำเนินการได้ตามปกติ

ตั้งแต่ `2026.1.10` เป็นต้นไป OpenClaw ยังระงับ **การสตรีมแบบร่าง/กำลังพิมพ์** เมื่อ
ชังก์บางส่วนเริ่มด้วย `NO_REPLY` เพื่อให้การทำงานแบบเงียบไม่รั่วไหลเอาต์พุตบางส่วน
ระหว่างเทิร์น

---

## "การล้างหน่วยความจำ" ก่อน Compaction (นำไปใช้แล้ว)

เป้าหมาย: ก่อน auto-compaction เกิดขึ้น ให้รันเทิร์นเอเจนต์แบบเงียบที่เขียนสถานะถาวร
ลงดิสก์ (เช่น `memory/YYYY-MM-DD.md` ในพื้นที่ทำงานของเอเจนต์) เพื่อให้ Compaction ไม่สามารถ
ลบบริบทสำคัญได้

OpenClaw ใช้แนวทาง **การล้างก่อนถึงเกณฑ์**:

1. ตรวจสอบการใช้งานบริบทของเซสชัน
2. เมื่อข้าม “เกณฑ์อ่อน” (ต่ำกว่าเกณฑ์ Compaction ของ Pi) ให้รันคำสั่งแบบเงียบ
   “เขียนหน่วยความจำตอนนี้” ไปยังเอเจนต์
3. ใช้โทเค็นเงียบที่ตรงกันทุกตัวอักษร `NO_REPLY` / `no_reply` เพื่อให้ผู้ใช้ไม่เห็น
   อะไรเลย

การกำหนดค่า (`agents.defaults.compaction.memoryFlush`):

- `enabled` (ค่าเริ่มต้น: `true`)
- `model` (การแทนที่ผู้ให้บริการ/โมเดลแบบตรงตัวสำหรับเทิร์นล้างข้อมูล ตัวอย่างเช่น `ollama/qwen3:8b`)
- `softThresholdTokens` (ค่าเริ่มต้น: `4000`)
- `prompt` (ข้อความผู้ใช้สำหรับเทิร์นล้างข้อมูล)
- `systemPrompt` (พรอมป์ระบบเพิ่มเติมที่ผนวกสำหรับเทิร์นล้างข้อมูล)

หมายเหตุ:

- พรอมป์เริ่มต้น/พรอมป์ระบบเริ่มต้นมีคำใบ้ `NO_REPLY` เพื่อระงับ
  การส่งมอบ
- เมื่อตั้งค่า `model` เทิร์นล้างข้อมูลจะใช้โมเดลนั้นโดยไม่สืบทอดเชน fallback
  ของเซสชันที่ใช้งานอยู่ ดังนั้นงานดูแลระบบเฉพาะเครื่องจะไม่ fallback แบบเงียบ
  ไปยังโมเดลสนทนาแบบเสียเงิน
- การล้างจะรันหนึ่งครั้งต่อรอบ Compaction (ติดตามใน `sessions.json`)
- การล้างจะรันเฉพาะสำหรับเซสชัน Pi แบบฝังตัว (แบ็กเอนด์ CLI จะข้าม)
- การล้างจะถูกข้ามเมื่อพื้นที่ทำงานของเซสชันเป็นแบบอ่านอย่างเดียว (`workspaceAccess: "ro"` หรือ `"none"`)
- ดู [หน่วยความจำ](/th/concepts/memory) สำหรับเลย์เอาต์ไฟล์พื้นที่ทำงานและรูปแบบการเขียน

Pi ยังเปิดเผยฮุก `session_before_compact` ใน API ของส่วนขยาย แต่ตรรกะการล้างของ OpenClaw
อยู่ฝั่ง Gateway ในปัจจุบัน

---

## เช็กลิสต์การแก้ปัญหา

- คีย์เซสชันผิดหรือไม่ เริ่มจาก [/concepts/session](/th/concepts/session) และยืนยัน `sessionKey` ใน `/status`
- Store กับทรานสคริปต์ไม่ตรงกันหรือไม่ ยืนยันโฮสต์ Gateway และพาธ store จาก `openclaw status`
- มี Compaction ถี่เกินไปหรือไม่ ตรวจสอบ:
  - หน้าต่างบริบทของโมเดล (เล็กเกินไป)
  - การตั้งค่า Compaction (`reserveTokens` สูงเกินไปสำหรับหน้าต่างโมเดลอาจทำให้ Compaction เกิดเร็วขึ้น)
  - ผลลัพธ์เครื่องมือพองเกิน: เปิดใช้/ปรับแต่งการตัดแต่งเซสชัน
- เทิร์นเงียบรั่วหรือไม่ ยืนยันว่าคำตอบเริ่มด้วย `NO_REPLY` (โทเค็นตรงตัวแบบไม่คำนึงถึงตัวพิมพ์เล็กใหญ่) และคุณอยู่บนบิลด์ที่มีการแก้ไขการระงับสตรีมมิงแล้ว

## ที่เกี่ยวข้อง

- [การจัดการเซสชัน](/th/concepts/session)
- [การตัดแต่งเซสชัน](/th/concepts/session-pruning)
- [เอนจินบริบท](/th/concepts/context-engine)
