Get started
ปรับโครงสร้างสถานะโดยยึดฐานข้อมูลเป็นหลัก
การปรับโครงสร้างสถานะแบบให้ฐานข้อมูลมาก่อน
การตัดสินใจ
ใช้เลย์เอาต์ SQLite สองระดับ:
- ฐานข้อมูลส่วนกลาง:
~/.openclaw/state/openclaw.sqlite - ฐานข้อมูล Agent: ฐานข้อมูล SQLite หนึ่งชุดต่อ Agent สำหรับพื้นที่ทำงานที่ Agent เป็นเจ้าของ, transcript, VFS, artifact และสถานะรันไทม์ขนาดใหญ่แบบต่อ Agent
- การกำหนดค่ายังคงอิงไฟล์:
openclaw.jsonยังคงอยู่นอก ฐานข้อมูล โปรไฟล์ยืนยันตัวตนรันไทม์ย้ายไป SQLite; ไฟล์ข้อมูลประจำตัวของ provider ภายนอกหรือ CLI ยังคงให้เจ้าของจัดการอยู่นอกฐานข้อมูลของ OpenClaw
ฐานข้อมูลส่วนกลางคือฐานข้อมูล control-plane โดยเป็นเจ้าของการค้นพบ Agent, สถานะ Gateway ที่ใช้ร่วมกัน, การจับคู่, สถานะอุปกรณ์/Node, บัญชีแยกประเภทงานและโฟลว์, สถานะ Plugin, สถานะรันไทม์ของตัวกำหนดเวลา, metadata การสำรองข้อมูล และสถานะการย้ายข้อมูล
ฐานข้อมูล Agent คือฐานข้อมูล data-plane โดยเป็นเจ้าของ metadata เซสชันของ Agent, สตรีมเหตุการณ์ transcript, พื้นที่ทำงาน VFS หรือ namespace scratch, artifact ของเครื่องมือ, artifact ของการรัน และข้อมูลแคชเฉพาะ Agent ที่ค้นหา/จัดทำดัชนีได้
สิ่งนี้ให้มุมมองส่วนกลางที่คงทนหนึ่งชุดโดยไม่บังคับพื้นที่ทำงาน Agent ขนาดใหญ่, transcript และข้อมูล scratch แบบไบนารีเข้าสู่ช่องทางเขียน Gateway ที่ใช้ร่วมกัน
สัญญาแบบเข้มงวด
การย้ายข้อมูลนี้มีรูปทรงรันไทม์มาตรฐานหนึ่งเดียว:
- แถวเซสชันเก็บเฉพาะ metadata ของเซสชันเท่านั้น ต้องไม่เก็บ
transcriptLocator, เส้นทางไฟล์ transcript, เส้นทาง JSONL พี่น้อง, เส้นทาง lock, metadata การ pruning หรือ pointer ความเข้ากันได้ยุคไฟล์ - ตัวตนของ transcript เป็นตัวตน SQLite เสมอ:
{agentId, sessionId}รวมถึง metadata หัวข้อแบบไม่บังคับเมื่อ protocol ต้องใช้ sqlite-transcript://...ไม่ใช่ตัวตนรันไทม์หรือ protocol โค้ดใหม่ต้อง ไม่ derive, persist, pass, parse หรือ migrate transcript locator รันไทม์และ การทดสอบไม่ควรมี pseudo-locator เลย; เอกสารอาจกล่าวถึงสตริงนี้ เฉพาะเพื่อห้ามใช้sessions.jsonเดิม, transcript JSONL,.jsonl.lock, pruning, truncation, และตรรกะ session-path เก่า อยู่ได้เฉพาะในเส้นทาง migration/import ของ doctor- alias config เซสชันเดิมอยู่ได้เฉพาะในการย้ายข้อมูลของ doctor รันไทม์ไม่
ตีความ
session.idleMinutes,session.resetByType.dmหรือ alias main-session ข้าม Agent แบบagent:main:*สำหรับ Agent อื่นที่กำหนดค่าไว้ - ตัวตนการกำหนดเส้นทางเซสชันเป็นสถานะเชิงสัมพันธ์ที่มีชนิด เส้นทางรันไทม์และ UI ที่ร้อน
ควรอ่าน
sessions.session_scope,sessions.account_id,sessions.primary_conversation_id,conversationsและsession_conversations; ต้องไม่ parsesession_keyหรือขุดsession_entries.entry_jsonเพื่อหาตัวตน provider ยกเว้นในฐานะเงาความเข้ากันได้ ระหว่างลบ call site เก่า - marker ข้อความโดยตรงระดับ channel เช่น
dmเทียบกับdirectเป็นคำศัพท์การกำหนดเส้นทาง ไม่ใช่ transcript locator หรือ handle ความเข้ากันได้ของ file-store - config hook handler เดิมอยู่ได้เฉพาะบนพื้นผิวคำเตือน/การย้ายข้อมูลของ doctor
รันไทม์ต้องไม่โหลด
hooks.internal.handlers; hook ทำงานผ่านไดเรกทอรี hook ที่ค้นพบ และ metadataHOOK.mdเท่านั้น - การเริ่มต้นรันไทม์, เส้นทางตอบกลับร้อน, Compaction, reset, recovery, diagnostics,
TTS, memory hooks, subagents, การกำหนดเส้นทางคำสั่ง Plugin, ขอบเขต protocol และ
hooks ต้องส่ง
{agentId, sessionId}ผ่านรันไทม์ - การทดสอบควร seed และ assert แถว transcript ของ SQLite ผ่าน
{agentId, sessionId}การทดสอบที่พิสูจน์เฉพาะการส่งต่อเส้นทาง JSONL, การคง locator ที่ caller ส่งมา หรือความเข้ากันได้ของไฟล์ transcript ควร ถูกลบ เว้นแต่ว่าครอบคลุม doctor import, การ materialize วัสดุ support/debug ที่ไม่ใช่เซสชัน หรือรูปทรง protocol runEmbeddedPiAgent(...), การรัน worker ที่เตรียมไว้ และ attempt แบบ embedded ภายใน ต้องไม่รับ transcript locator ต้องเปิดตัวจัดการ transcript SQLite ด้วย{agentId, sessionId}และส่งตัวจัดการนั้นให้เซสชัน Agent ที่เข้ากันได้กับ PI ซึ่ง internalize แล้ว เพื่อไม่ให้ caller เก่าทำให้ runner เขียน transcript JSON/JSONL ได้- diagnostics ของ runner ต้องเก็บระเบียน trace runtime/cache/payload ใน SQLite diagnostics รันไทม์ต้องไม่เปิดเผย knob override ไฟล์ JSONL หรือ helper export transcript JSONL แบบทั่วไป; export ที่ผู้ใช้เห็นสามารถ materialize artifact ที่ชัดเจน จากแถวฐานข้อมูลโดยไม่ป้อนชื่อไฟล์กลับเข้าสู่รันไทม์
- การบันทึก raw stream ใช้
OPENCLAW_RAW_STREAM=1พร้อมแถว diagnostics ของ SQLite สัญญา file logger เดิมของ pi-mono ได้แก่PI_RAW_STREAM,PI_RAW_STREAM_PATHและraw-openai-completions.jsonlไม่เป็นส่วนหนึ่งของรันไทม์หรือการทดสอบของ OpenClaw - การทำดัชนีหน่วยความจำ QMD ต้องไม่ export transcript SQLite เป็นไฟล์ markdown QMD จัดทำดัชนีเฉพาะไฟล์หน่วยความจำที่กำหนดค่าไว้; การค้นหา transcript เซสชันยังคง อิง SQLite
- subpath ของ QMD SDK เป็นของ QMD เท่านั้นสำหรับโค้ดใหม่ helper การทำดัชนี transcript
เซสชัน SQLite อยู่บน
memory-core-host-engine-session-transcripts; การ re-export ของ QMD ใดๆ เป็นเพียงความเข้ากันได้และต้องไม่ถูกใช้โดยโค้ดรันไทม์ - ดัชนีหน่วยความจำในตัวอยู่ในฐานข้อมูล Agent ที่เป็นเจ้าของ config รันไทม์และ
สัญญารันไทม์ที่ resolve แล้วต้องไม่เปิดเผย
memorySearch.store.path; doctor ลบคีย์ config เดิมนั้น และโค้ดปัจจุบันส่งdatabasePathของ Agent ภายใน
งาน implement ควรลบโค้ดต่อไปจนกว่าข้อความเหล่านี้จะเป็นจริง โดยไม่มีข้อยกเว้นนอกขอบเขต doctor/import/export/debug
สถานะเป้าหมายและความคืบหน้า
เป้าหมายเข้มงวด
- ฐานข้อมูล SQLite ส่วนกลางหนึ่งชุดเป็นเจ้าของสถานะ control-plane:
state/openclaw.sqlite - ฐานข้อมูล SQLite แบบต่อ Agent หนึ่งชุดเป็นเจ้าของสถานะ data-plane:
agents/<agentId>/agent/openclaw-agent.sqlite - config ยังคงอิงไฟล์
openclaw.jsonไม่เป็นส่วนหนึ่งของการปรับโครงสร้าง ฐานข้อมูลนี้ - ไฟล์เดิมเป็นเพียงอินพุตการย้ายข้อมูลของ doctor
- รันไทม์ไม่เขียนหรืออ่าน JSONL ของเซสชันหรือ transcript เป็นสถานะ active
สถานะเป้าหมาย
not-started: โค้ดรันไทม์ยุคไฟล์ยังคงเขียนสถานะ activemigrating: โค้ด doctor/import สามารถย้ายข้อมูลไฟล์เข้า SQLitedual-read: สะพานชั่วคราวอ่านทั้ง SQLite และไฟล์เดิม สถานะนี้ ถูกห้ามสำหรับการปรับโครงสร้างนี้ เว้นแต่จะมีเอกสารระบุชัดเจนว่า เป็น doctor-onlysqlite-runtime: รันไทม์อ่านและเขียนเฉพาะ SQLiteclean: API และการทดสอบรันไทม์เดิมถูกลบ และ guard ป้องกัน regressiondone: เอกสาร, การทดสอบ, การสำรองข้อมูล, การย้ายข้อมูล doctor และ changed checks พิสูจน์ สถานะ clean
สถานะปัจจุบัน
- Sessions:
cleanสำหรับรันไทม์ แถวเซสชันอยู่ในฐานข้อมูลแบบต่อ Agent, API รันไทม์ใช้{agentId, sessionId}หรือ{agentId, sessionKey}และsessions.jsonเป็นอินพุต legacy ของ doctor เท่านั้น - Transcripts:
cleanสำหรับรันไทม์ เหตุการณ์ transcript, ตัวตน, snapshot และเหตุการณ์รันไทม์ trajectory อยู่ในฐานข้อมูลแบบต่อ Agent รันไทม์ไม่ รับ transcript locator หรือเส้นทาง transcript JSONL อีกต่อไป - PI embedded runner:
cleanการรัน PI แบบ embedded, worker ที่เตรียมไว้, Compaction และลูป retry ใช้ scope เซสชัน SQLite และปฏิเสธ handle transcript เก่า - Cron:
cleanสำหรับรันไทม์ รันไทม์ใช้cron_jobsและcron_run_logs; การทดสอบรันไทม์ใช้การตั้งชื่อstoreKeyแบบ SQLite และเส้นทาง Cron ยุคไฟล์ยังคงอยู่ใน การทดสอบ migration legacy ของ doctor เท่านั้น - Task registry:
cleanแถวรันไทม์ของ Task และ Task Flow อยู่ในstate/openclaw.sqlite; importer SQLite sidecar ที่ยังไม่ shipped ถูกลบแล้ว - สถานะ Plugin:
cleanแถวสถานะ/blob ของ Plugin อยู่ในฐานข้อมูลส่วนกลางที่ใช้ร่วมกัน; helper SQLite sidecar ของสถานะ Plugin เก่าถูก guard ไว้ - Memory:
sqlite-runtimeสำหรับหน่วยความจำในตัวและการทำดัชนี transcript เซสชัน ตารางดัชนีหน่วยความจำอยู่ในฐานข้อมูลแบบต่อ Agent, สถานะหน่วยความจำ Plugin ใช้ แถว plugin-state ที่ใช้ร่วมกัน และไฟล์หน่วยความจำเดิมเป็นอินพุตการย้ายข้อมูลของ doctor หรือเนื้อหา workspace ของผู้ใช้ - Backup:
sqlite-runtimeขั้นตอนสำรองข้อมูล compact snapshot SQLite, ละเว้น WAL/SHM sidecar ที่ยังทำงานอยู่, ตรวจสอบ integrity ของ SQLite และบันทึกการรัน backup ใน ฐานข้อมูลส่วนกลาง - การย้ายข้อมูล doctor:
migratingโดยตั้งใจ doctor import JSON legacy, JSONL และ store sidecar ที่เลิกใช้แล้วเข้า SQLite, บันทึกการรัน/แหล่งที่มาของ migration และลบแหล่งที่มาที่สำเร็จ - สคริปต์ E2E:
cleanสำหรับความครอบคลุมรันไทม์ การ seed Docker MCP เขียนแถว SQLite สคริปต์ Docker runtime-context สร้าง JSONL legacy เฉพาะใน seed การย้ายข้อมูลของ doctor และตั้งชื่อเส้นทางดัชนีเซสชัน legacy อย่างชัดเจน
งานที่เหลือ
- [x] เปลี่ยนชื่อ variable store ของการทดสอบรันไทม์ Cron ออกจาก
storePathเว้นแต่ จะเป็นอินพุต legacy ของ doctor ไฟล์:src/cron/service.test-harness.ts,src/cron/service.runs-one-shot-main-job-disables-it.test.ts,src/cron/service/timer.regression.test.ts,src/cron/service/ops.test.ts,src/cron/service/store.test.ts,src/cron/service.heartbeat-ok-summary-suppressed.test.ts,src/cron/service.main-job-passes-heartbeat-target-last.test.ts,src/cron/store.test.tsหลักฐาน:pnpm check:database-first-legacy-stores;rg -n 'storePath' src/cron --glob '!**/commands/doctor/**' - [x] ลบหรือเปลี่ยนชื่อ mock การทดสอบ export ยุคไฟล์ที่ล้าสมัย
ไฟล์:
src/auto-reply/reply/commands-export-test-mocks.tsหลักฐาน:rg -n 'resolveSessionFilePath|sessionFile|storePath|transcriptLocator' src/auto-reply/reply - [x] ทำให้ seed JSONL legacy ของ Docker runtime-context ชัดเจนว่าเป็น doctor-only
ไฟล์:
scripts/e2e/session-runtime-context-docker-client.tsหลักฐาน:rg -n 'sessions\\.json|sessionFile|\\.jsonl' scripts/e2e/session-runtime-context-docker-client.tsแสดงเฉพาะseedBrokenLegacySessionForDoctorMigration - [x] รักษา type ที่ generated โดย Kysely ให้ตรงหลังการเปลี่ยนแปลง schema ใดๆ
ไฟล์:
src/state/openclaw-state-schema.sql,src/state/openclaw-agent-schema.sql,src/state/*generated*หลักฐาน: ไม่มีการเปลี่ยนแปลง schema ในรอบนี้;pnpm db:kysely:check;pnpm lint:kysely - [x] รันการทดสอบแบบโฟกัสซ้ำสำหรับ store, command และสคริปต์ที่แตะ
หลักฐาน:
pnpm test src/cron/service/store.test.ts src/cron/store.test.ts src/cron/service.heartbeat-ok-summary-suppressed.test.ts src/cron/service.main-job-passes-heartbeat-target-last.test.ts src/cron/service.every-jobs-fire.test.ts src/cron/service.persists-delivered-status.test.ts src/cron/service.runs-one-shot-main-job-disables-it.test.ts src/cron/service/ops.test.ts src/cron/service/timer.regression.test.ts src/auto-reply/reply/commands-export-trajectory.test.ts extensions/telegram/src/thread-bindings.test.ts extensions/slack/src/monitor/message-handler/prepare.test.ts src/acp/translator.session-lineage-meta.test.ts;git diff --check - [x] ก่อนประกาศ
done, รัน changed gate หรือ broad proof ระยะไกล หลักฐาน:pnpm check:changed --timed -- <changed extension paths>ผ่านบน Hetzner Crabbox runrun_3f1cabf6b25cหลังการตั้งค่า Node 24/pnpm ชั่วคราวและ การกำหนดเส้นทาง path ชัดเจนสำหรับ workspace ที่ sync แล้วซึ่งไม่มี.git
อย่าให้ถดถอย
- ไม่มี transcript locator
- ไม่มีไฟล์เซสชัน active
- ไม่มี fixture ทดสอบ JSONL ปลอม ยกเว้นการทดสอบ migration legacy ของ doctor
- ไม่มีการเข้าถึง SQLite แบบ raw ในที่ที่คาดหวัง Kysely
- ไม่มีการย้ายข้อมูล DB legacy ใหม่ เลย์เอาต์นี้ยังไม่ได้ shipped; คง schema version
ไว้ที่
1เว้นแต่จะมีเหตุผลหนักแน่น
สมมติฐานจากการอ่านโค้ด
ไม่มีการตัดสินใจผลิตภัณฑ์เพิ่มเติมที่บล็อกแผนนี้ การ implement ควร ดำเนินต่อด้วยสมมติฐานเหล่านี้:
- ใช้
node:sqliteโดยตรงและกำหนดให้เส้นทางพื้นที่จัดเก็บนี้ต้องใช้ runtime Node 22+ - เก็บไฟล์การกำหนดค่าปกติไว้เพียงไฟล์เดียวเท่านั้น อย่าย้าย config, plugin manifests หรือ Git workspaces เข้าไปใน SQLite ในการ refactor นี้
- ไม่จำเป็นต้องมีไฟล์ความเข้ากันได้ของ runtime ไฟล์ JSON และ JSONL แบบ legacy เป็นเพียงอินพุตสำหรับ migration เท่านั้น ส่วน SQLite sidecars แบบ branch-local ไม่เคยถูกเผยแพร่และจะถูกลบแทนการ import
openclaw doctor --fixเป็นเจ้าของขั้นตอน migration จากไฟล์ legacy ไปยังฐานข้อมูล การเริ่มต้น runtime และopenclaw migrateไม่ควรแบกรับเส้นทางอัปเกรดฐานข้อมูล OpenClaw แบบ legacy- ความเข้ากันได้ของ credential ใช้กฎเดียวกัน: credential ของ runtime อยู่ใน
SQLite ไฟล์เก่า
auth-profiles.json,auth.jsonราย agent และไฟล์ร่วมcredentials/oauth.jsonเป็นอินพุตสำหรับ doctor migration จากนั้นจะถูกลบ หลัง import - สถานะ catalog ของโมเดลที่สร้างขึ้นต้องมีฐานข้อมูลรองรับ โค้ด runtime ต้องไม่เขียน
agents/<agentId>/agent/models.json; ไฟล์models.jsonที่มีอยู่เป็นอินพุต legacy สำหรับ doctor และจะถูกลบหลัง import เข้าagent_model_catalogs - Runtime ต้องไม่ migrate, normalize หรือ bridge transcript locators ตัวตนของ
transcript ที่ active คือ
{agentId, sessionId}ใน SQLite เส้นทางไฟล์เป็นเพียง อินพุต legacy สำหรับ doctor และsqlite-transcript://...ต้องหายไปจากพื้นผิว runtime, protocol, hook และ plugin แทนที่จะถูกถือเป็น boundary handle - การอ่าน transcript จาก SQLite ใน runtime จะไม่รัน migration รูปทรง entry แบบ JSONL เก่าหรือเขียน transcript ทั้งหมดใหม่เพื่อความเข้ากันได้ การ normalize entry แบบ legacy อยู่ในยูทิลิตี doctor/import ที่ชัดเจนเท่านั้น Doctor จะ normalize ไฟล์ transcript JSONL แบบ legacy ก่อนแทรกแถว SQLite; แถว runtime ปัจจุบันถูกเขียน ด้วย schema transcript ปัจจุบันอยู่แล้ว การ export trajectory/session อ่านแถวเหล่านั้น ตามเดิมและต้องไม่ทำ migration legacy ระหว่าง export
- helper สำหรับ parse/migration transcript JSONL แบบ legacy เป็นของ doctor เท่านั้น โค้ดรูปแบบ transcript ของ runtime สร้าง context transcript SQLite ปัจจุบันเท่านั้น; doctor เป็นเจ้าของการอัปเกรด entry JSONL เก่าก่อนแทรกแถว
- helper streaming transcript JSONL เดิมที่ runtime เป็นเจ้าของถูกลบแล้ว โค้ด import ของ doctor เป็นเจ้าของการอ่านไฟล์ legacy อย่างชัดเจน; ประวัติ session ของ runtime อ่านแถว SQLite
- binding ของ Codex app-server ใช้
sessionIdของ OpenClaw เป็นคีย์ canonical ใน namespace plugin-state ของ CodexsessionKeyเป็น metadata สำหรับ routing/display และต้องไม่แทนที่ session id ที่คงทนหรือทำให้ตัวตน transcript-file กลับมา - context engines ได้รับ contract runtime ปัจจุบันโดยตรง registry ต้องไม่ wrap engine
ด้วย retry shims ที่ลบ
sessionKey,transcriptScopeหรือprompt; engine ที่รับ params ปัจจุบันแบบ database-first ไม่ได้ควร fail loudly แทนที่จะถูก bridge - เอาต์พุต backup ควรยังเป็นไฟล์ archive เดียว เนื้อหาฐานข้อมูลควรเข้า archive นั้น เป็น snapshot SQLite แบบ compact ไม่ใช่ live WAL sidecars ดิบ
- การค้นหา transcript มีประโยชน์แต่ไม่จำเป็นสำหรับรอบแรกแบบ database-first ให้ออกแบบ schema เพื่อให้เพิ่ม FTS ได้ในภายหลัง
- การทำงานของ worker ควรยังคงเป็น experimental อยู่หลัง settings ระหว่างที่ boundary ของฐานข้อมูลยังนิ่งตัว
สิ่งที่พบจากการอ่านโค้ด
branch ปัจจุบันผ่านขั้น proof-of-concept มาแล้ว ฐานข้อมูลร่วมมีอยู่จริง, Node
node:sqlite ถูกเชื่อมผ่าน helper runtime ขนาดเล็ก และ store เดิมตอนนี้เขียนไปที่
state/openclaw.sqlite หรือฐานข้อมูล openclaw-agent.sqlite ของเจ้าของ
งานที่เหลือไม่ใช่การเลือก SQLite แต่คือการรักษา boundary ใหม่ให้สะอาดและลบ interface รูปทรงความเข้ากันได้ที่ยังดูเหมือนโลกไฟล์เก่า:
- Session
storePathไม่ใช่ตัวตน runtime, รูปทรง test fixture หรือฟิลด์ status payload อีกต่อไป การทดสอบ runtime และ bridge ไม่มีชื่อ contractstorePathแล้ว; โค้ด doctor/migration เป็นเจ้าของคำศัพท์ legacy นั้น - การเขียน session ไม่ผ่าน queue
store-writer.tsแบบ in-process เดิมอีกต่อไป การเขียน patch ของ SQLite ใช้ conflict detection และ bounded retry แทน - การค้นหาเส้นทาง legacy ยังมีการใช้งานด้าน migration ที่ถูกต้อง แต่โค้ด runtime ควรหยุด
ถือว่า
sessions.jsonและไฟล์ transcript JSONL เป็นเป้าหมายการเขียนที่เป็นไปได้ - ตารางที่ agent เป็นเจ้าของอยู่ในฐานข้อมูล SQLite ราย agent ฐานข้อมูล global เก็บแถว
registry/control-plane; ตัวตน transcript คือ
{agentId, sessionId}ในแถว transcript ราย agent โค้ด runtime ต้องไม่ persist เส้นทางไฟล์ transcript หรือ migrate transcript locators - Doctor import ไฟล์ legacy หลายไฟล์อยู่แล้ว การ cleanup คือทำให้สิ่งนั้นเป็น implementation migration แบบชัดเจนเพียงชุดเดียวที่ doctor เรียกใช้ พร้อมรายงาน migration ที่คงทน
ไม่มีคำถามด้านผลิตภัณฑ์เพิ่มเติมที่ขวางการ implement
รูปทรงโค้ดปัจจุบัน
branch นี้มีฐาน SQLite ร่วมที่ใช้งานจริงแล้ว:
- พื้นฐานรันไทม์ขั้นต่ำตอนนี้คือ Node 22+:
package.json, ตัวป้องกันรันไทม์ของ CLI, ค่าเริ่มต้นของตัวติดตั้ง, ตัวค้นหารันไทม์บน macOS, CI และเอกสารการติดตั้งสาธารณะทั้งหมด สอดคล้องกันแล้ว เลนความเข้ากันได้กับ Node 22 แบบเก่าถูกนำออกแล้ว src/state/openclaw-state-db.tsเปิดopenclaw.sqlite, ตั้งค่า WAL,synchronous=NORMAL,busy_timeout=30000,foreign_keys=ONและใช้ โมดูลสคีมาที่สร้างขึ้นซึ่งได้มาจากsrc/state/openclaw-state-schema.sql- ประเภทตาราง Kysely และโมดูลสคีมารันไทม์ถูกสร้างจากฐานข้อมูล
SQLite แบบใช้แล้วทิ้งที่สร้างจากไฟล์
.sqlที่ commit ไว้; โค้ดรันไทม์จะไม่เก็บ สตริงสคีมาที่คัดลอกวางไว้เองสำหรับฐานข้อมูลส่วนกลาง, ต่อเอเจนต์ หรือ proxy capture อีกต่อไป - สโตร์รันไทม์ได้ประเภทแถวที่เลือกและแทรกจากอินเทอร์เฟซ Kysely
DBที่สร้างขึ้นเหล่านั้น แทนการสะท้อนรูปทรงแถว SQLite ด้วยมือ Raw SQL ยังคงจำกัดไว้เฉพาะการใช้สคีมา, pragmas และ DDL เฉพาะการย้ายข้อมูลเท่านั้น - สคีมา SQLite ถูกยุบเหลือ
user_version = 1เพราะเลย์เอาต์ฐานข้อมูลนี้ ยังไม่เคยถูกปล่อยใช้งานจริง ตัวเปิดรันไทม์สร้างเฉพาะสคีมาปัจจุบัน; การนำเข้าจากไฟล์สู่ฐานข้อมูลยังอยู่ในโค้ด doctor และ helper อัปเกรด ฐานข้อมูลเฉพาะ branch ถูกลบแล้ว - ความเป็นเจ้าของเชิงสัมพันธ์ถูกบังคับใช้ในจุดที่ขอบเขตความเป็นเจ้าของเป็น canonical:
แถวการย้ายแหล่งที่มาจะ cascade จาก
migration_runs, สถานะการส่ง task จะ cascade จากtask_runsและแถวตัวตน transcript จะ cascade จาก เหตุการณ์ transcript - ตาราง shared ปัจจุบันรวมถึง
agent_databases,auth_profile_stores,auth_profile_state,plugin_state_entries,plugin_blob_entries,media_blobs,skill_uploads,capture_sessions,capture_events,capture_blobs,sandbox_registry_entries,cron_run_logs,cron_jobs,commitments,delivery_queue_entries,model_capability_cache,workspace_setup_state,native_hook_relay_bridges,current_conversation_bindings,plugin_binding_approvals,tui_last_sessions,acp_sessions,acp_replay_sessions,acp_replay_events,task_runs,task_delivery_state,flow_runs,subagent_runs,migration_runsและbackup_runs - สถานะใดๆ ที่ Plugin เป็นเจ้าของจะไม่ได้ตาราง typed ที่ host เป็นเจ้าของ
Plugin ที่ติดตั้งใช้
plugin_state_entriesสำหรับ payload JSON แบบมีเวอร์ชัน และplugin_blob_entriesสำหรับ bytes พร้อมความเป็นเจ้าของ namespace/key, การล้าง TTL, backup และระเบียนการย้ายข้อมูลของ Plugin สถานะ orchestration ของ Plugin ที่ host เป็นเจ้าของ ยังมีตาราง typed ได้เมื่อ host เป็นเจ้าของสัญญาการ query เช่นplugin_binding_approvals - การย้ายข้อมูลของ Plugin คือการย้ายข้อมูลเหนือ namespace ที่ Plugin เป็นเจ้าของ ไม่ใช่
การย้ายสคีมาของ host Plugin สามารถย้าย state/blob entries แบบมีเวอร์ชันของตนเอง
ผ่าน migration provider ได้ และ host จะบันทึกสถานะ source/run ใน
ledger การย้ายข้อมูลปกติ การติดตั้ง Plugin ใหม่ไม่จำเป็นต้องเปลี่ยน
openclaw-state-schema.sqlเว้นแต่ host เองจะรับความเป็นเจ้าของ สัญญาข้าม Plugin ใหม่ src/state/openclaw-agent-db.tsเปิดagents/<agentId>/agent/openclaw-agent.sqlite, ลงทะเบียนฐานข้อมูลใน DB ส่วนกลาง และเป็นเจ้าของตาราง session, transcript, VFS, artifact, cache และ memory-index ในเครื่องเอเจนต์ ขณะนี้การค้นพบรันไทม์ shared อ่านรีจิสทรีagent_databasesที่มี typed ที่สร้างไว้แล้ว แทนการทำ query นั้นซ้ำในแต่ละ call site- ฐานข้อมูลส่วนกลางและต่อเอเจนต์บันทึกแถว
schema_metaพร้อมบทบาทฐานข้อมูล, เวอร์ชันสคีมา, timestamps และ agent id สำหรับฐานข้อมูลเอเจนต์ เลย์เอาต์ยังคงอยู่ที่user_version = 1เพราะสคีมา SQLite นี้ยังไม่เคยถูกปล่อยใช้งานจริง - ตัวตน session ต่อเอเจนต์ตอนนี้มีตารางราก canonical
sessionsที่ใช้session_idเป็น key พร้อมsession_key,session_scope,account_id,primary_conversation_id, timestamps, display fields, metadata ของ model, harness id และลิงก์ parent/spawn เป็นคอลัมน์ที่ query ได้session_routesคือดัชนี route ที่ใช้งานอยู่แบบ unique จากsession_keyไปยังsession_idปัจจุบัน เพื่อให้ route key ย้ายไปยัง session durable ใหม่ได้โดยไม่ทำให้ hot reads ต้องเลือกระหว่างแถวsessions.session_keyที่ซ้ำกัน payload รูปทรงเข้ากันได้เก่าsession_entries.entry_jsonผูกกับราก durablesession_idด้วย foreign key; มันไม่ใช่ตัวแทนของ session เพียงตัวเดียวในระดับสคีมาอีกต่อไป - ตัวตนการสนทนาภายนอกต่อเอเจนต์ก็เป็นเชิงสัมพันธ์เช่นกัน:
conversationsเก็บตัวตน provider/account/conversation ที่ normalize แล้ว และsession_conversationsเชื่อมหนึ่ง session ของ OpenClaw กับการสนทนาภายนอกหนึ่งรายการหรือมากกว่า สิ่งนี้ครอบคลุม session DM แบบ shared-main ที่ peer หลายรายสามารถตั้งใจ map ไปยัง session เดียว โดยไม่โกหกในsession_keySQLite ยังบังคับ uniqueness สำหรับตัวตน provider ตามธรรมชาติ เพื่อไม่ให้ tuple channel/account/kind/peer/thread เดียวกันแตกออกเป็น conversation ids หลายรายการได้ peer แบบ direct ของ shared-main ถูกลิงก์ด้วย roleparticipantเพื่อให้หนึ่ง session ของ OpenClaw แทน peer DM ภายนอกหลายรายได้โดยไม่ลดสถานะ peer เก่า เป็นแถว related ที่คลุมเครือsessions.primary_conversation_idยังชี้ไปที่ เป้าหมายการส่งแบบ typed ปัจจุบัน คอลัมน์ routing/status แบบปิดถูกบังคับใช้ด้วย ข้อจำกัด SQLiteCHECKแทนการพึ่งพาเพียง union ของ TypeScript การฉาย session รันไทม์ล้างเงา routing สำหรับความเข้ากันได้จากsession_entries.entry_jsonก่อนใช้คอลัมน์ session/conversation แบบ typed เพื่อไม่ให้ payload JSON เก่าปลุกเป้าหมายการส่งกลับมาได้ การ routing การประกาศของ subagent ก็ต้องใช้บริบทการส่งแบบ typed ของ SQLite เช่นกัน; มันไม่ fallback ไปยัง field route ของSessionEntryเพื่อความเข้ากันได้อีกต่อไป การสืบทอดการส่งแบบชัดเจนของ Gatewaychat.sendอ่านบริบทการส่งแบบ typed ของ SQLite แทน field ความเข้ากันได้origin/last*tools.effectiveก็ได้บริบท provider/account/thread จากแถวการส่ง/routing แบบ typed ของ SQLite ไม่ใช่เงา session-entrylast*ที่ค้างอยู่ บริบท prompt ของเหตุการณ์ระบบสร้าง field channel/to/account/thread ใหม่จาก field การส่งแบบ typed แทนเงาoriginhelper shareddeliveryContextFromSessionและ mapper session-to-conversation ตอนนี้ละเว้นSessionEntry.originทั้งหมด; เฉพาะ field การส่งแบบ typed และแถว conversation เชิงสัมพันธ์เท่านั้นที่สร้างตัวตน hot route ได้ การ normalize entry ของ session รันไทม์จะตัดoriginออกก่อน persist หรือ projectentry_jsonและการเขียน metadata ขาเข้าจะเขียน field channel/chat แบบ typed พร้อมแถว conversation เชิงสัมพันธ์ แทนการสร้างเงา origin ใหม่ - เหตุการณ์ transcript, snapshots ของ transcript และเหตุการณ์รันไทม์ trajectory ตอนนี้
อ้างอิงราก
sessionscanonical ต่อเอเจนต์และ cascade เมื่อ session ถูกลบ แถวตัวตน/idempotency ของ transcript ยังคง cascade จาก แถวเหตุการณ์ transcript ที่ตรงกัน - ดัชนี memory-core ตอนนี้ใช้ตารางฐานข้อมูลเอเจนต์ที่ชัดเจน
memory_index_meta,memory_index_sources,memory_index_chunksและmemory_embedding_cacheโดยmemory_index_stateติดตามการเปลี่ยนแปลง revision ดัชนีข้าง FTS/vector แบบ optional มีชื่อว่าmemory_index_chunks_ftsและmemory_index_chunks_vecแทนตาราง genericmeta,files,chunks,chunks_ftsหรือchunks_vecชื่อ canonical ยังคงรูปทรงแถว path/source ปัจจุบันและความเข้ากันได้ของ embedding ที่ serialize แล้ว ตารางเหล่านี้เป็น derived/search cache ไม่ใช่ที่เก็บ transcript canonical; สามารถลบและสร้างใหม่ จากไฟล์ workspace memory และแหล่งที่กำหนดค่าได้ การเปิดดัชนี memory ชื่อ generic ที่เคยปล่อยใช้งานแล้วจะย้าย metadata, sources, chunks และ embedding cache ไปยังตาราง canonical; ตาราง FTS/vector ที่ได้มาจะถูกสร้างใหม่ภายใต้ชื่อ canonical - สถานะการกู้คืนการรัน subagent ตอนนี้อยู่ในแถว shared
subagent_runsแบบ typed พร้อมคีย์ session ของ child, requester และ controller ที่ทำดัชนีไว้ ไฟล์เก่าsubagents/runs.jsonเป็นเพียงอินพุตการย้ายข้อมูลของ doctor เท่านั้น - bindings ของการสนทนาปัจจุบันตอนนี้อยู่ในแถว shared
current_conversation_bindingsแบบ typed ซึ่ง key ด้วย conversation id ที่ normalize แล้ว พร้อม คอลัมน์ agent/session เป้าหมาย, ชนิดการสนทนา, สถานะ, expiry และ metadata ที่เก็บเป็นคอลัมน์เชิงสัมพันธ์แทนระเบียน binding ทึบแสงที่ซ้ำกัน key ของ binding แบบ durable รวมชนิดการสนทนาที่ normalize แล้วไว้ด้วย เพื่อให้ refs direct/group/channel ไม่ชนกัน และ SQLite ปฏิเสธค่า binding kind/status ที่ไม่ถูกต้อง ไฟล์เก่าbindings/current-conversations.jsonเป็นเพียงอินพุตการย้ายข้อมูลของ doctor เท่านั้น - การกู้คืนคิวการส่งตอนนี้ overlay คอลัมน์คิวแบบ typed สำหรับ channel, target,
account, session, retry, error, platform-send และสถานะ recovery ลงบน
replay JSON
entry_jsonเก็บ payload replay, hooks และ payload formatting ไว้ แต่คอลัมน์ typed เป็น authoritative สำหรับ routing/state ของ hot queue - pointers สำหรับ restore session ล่าสุดของ TUI ตอนนี้อยู่ในแถว shared
tui_last_sessionsแบบ typed ซึ่ง key ด้วย scope ของการเชื่อมต่อ/session TUI ที่ hash แล้ว ไฟล์ JSON ของ TUI เก่าเป็นเพียงอินพุตการย้ายข้อมูลของ doctor เท่านั้น - prefs เริ่มต้นของ TTS ตอนนี้อยู่ในแถว SQLite ของ plugin-state shared ซึ่ง key ภายใต้
Plugin
speech-coreไฟล์เก่าsettings/tts.jsonเป็นเพียงอินพุตการย้ายข้อมูลของ doctor เท่านั้น; รันไทม์ไม่อ่านหรือเขียนไฟล์ JSON prefs ของ TTS อีกต่อไป และ resolver ของ path เก่าอยู่ในโมดูลการย้ายข้อมูลของ doctor - metadata ของ secret target ตอนนี้พูดถึงสโตร์แทนการแสร้งว่าทุก
credential target เป็นไฟล์ config
openclaw.jsonยังคงเป็น config store; target ของ auth-profile ใช้แถว SQLiteauth_profile_storesแบบ typed พร้อม credentials รูปทรง provider ที่เก็บเป็น payload JSON - การ audit secret ไม่สแกนไฟล์
auth.jsonต่อเอเจนต์ที่เลิกใช้แล้วอีกต่อไป Doctor เป็นเจ้าของ การเตือน การนำเข้า และการลบไฟล์ legacy นั้น - helper path ของ auth profile legacy ตอนนี้อยู่ในโค้ด legacy ของ doctor helper path ของ core auth
profile เปิดเผยตัวตนของ SQLite auth-store และตำแหน่งแสดงผล
ไม่ใช่ path รันไทม์
auth-profiles.jsonหรือauth-state.json - โมดูลรันไทม์การกู้คืนการรัน subagent และ cache ความสามารถของ model OpenRouter
ตอนนี้แยก snapshot readers/writers ของ SQLite ออกจาก helper นำเข้า JSON legacy ที่มีเฉพาะ doctor
ความสามารถของ OpenRouter ใช้แถว generic
model_capability_cacheแบบ typed ภายใต้provider_id = "openrouter"แทน blob cache ทึบแสงหนึ่งก้อนหรือตาราง host เฉพาะ provider การรัน subagenttaskNameถูกเก็บในคอลัมน์ typedsubagent_runs.task_name; สำเนาpayload_jsonเป็นข้อมูล replay/debug ไม่ใช่แหล่งที่มาสำหรับ hot display หรือ field lookup src/agents/filesystem/virtual-agent-fs.sqlite.tsใช้งาน SQLite VFS เหนือตารางvfs_entriesของฐานข้อมูลเอเจนต์ การอ่าน directory, exports แบบ recursive, การลบ และการ rename ใช้ช่วง prefix(namespace, path)ที่ทำดัชนีแล้ว แทนการสแกนทั้ง namespace หรือพึ่งพาการจับคู่ path ด้วยLIKEsrc/agents/runtime-worker.entry.tsสร้าง SQLite VFS ต่อ run, tool artifact, run artifact และ scoped cache stores สำหรับ workers- markers การเสร็จสิ้น bootstrap ของ workspace ตอนนี้อยู่ในแถว shared
workspace_setup_stateแบบ typed ซึ่ง key ด้วย path workspace ที่ resolve แล้ว แทน.openclaw/workspace-state.json; รันไทม์ไม่อ่านหรือเขียน marker workspace legacy อีกต่อไป และ API helper ไม่ส่ง path ปลอม.openclaw/setup-stateไปมาเพียงเพื่อหา identity ของ storage อีกต่อไป - exec approvals ตอนนี้อยู่ในแถว singleton ของ SQLite shared แบบ typed
exec_approvals_configDoctor นำเข้า legacy~/.openclaw/exec-approvals.json; การเขียนของรันไทม์ไม่สร้าง, เขียนซ้ำ หรือรายงานไฟล์นั้นเป็นตำแหน่งสโตร์ที่ active อีกต่อไป companion บน macOS อ่านและเขียนแถวตารางstate/openclaw.sqliteเดียวกัน; มันเก็บไว้บนดิสก์เฉพาะ Unix prompt socket เพราะนั่นคือ IPC ไม่ใช่สถานะรันไทม์ durable - โมดูลรันไทม์ของ device identity, device auth และ bootstrap ตอนนี้แยก
snapshot readers/writers ของ SQLite ออกจาก helper นำเข้า JSON legacy ที่มีเฉพาะ doctor
Device identity ใช้แถว
device_identitiesแบบ typed และ token ของ device auth ใช้แถวdevice_auth_tokensแบบ typed การเขียน device auth จะ reconcile แถว ตาม device/role แทนการ truncate ตาราง token และรันไทม์ไม่ route การอัปเดต token เดี่ยวผ่าน adapter whole-store เก่าอีกต่อไป Legacy เพย์โหลด JSON version-1 มีอยู่เฉพาะในรูปแบบนำเข้า/ส่งออกของ doctor เท่านั้น. - แคชการแลกเปลี่ยนโทเค็น GitHub Copilot ใช้ตารางสถานะ Plugin ของ SQLite ที่ใช้ร่วมกัน
ภายใต้
github-copilot/token-cache/defaultนี่เป็นสถานะแคชที่ผู้ให้บริการเป็นเจ้าของ จึงตั้งใจไม่เพิ่มตารางสคีมาของโฮสต์. - Compaction ของ GitHub Copilot จะไม่เขียนไฟล์เสริมเวิร์กสเปซ
openclaw-compaction-*.jsonอีกต่อไป ฮาร์เนสเรียก RPC ของ compaction ประวัติ SDK สำหรับ เซสชัน SDK ที่ติดตาม และ OpenClaw เก็บสถานะเซสชัน/ทรานสคริปต์แบบคงทนใน SQLite แทนไฟล์มาร์กเกอร์ความเข้ากันได้. - รันไทม์ Swift ที่ใช้ร่วมกัน (
OpenClawKit) ใช้แถวstate/openclaw.sqliteเดียวกันสำหรับตัวตนอุปกรณ์และการยืนยันตัวตนอุปกรณ์ ตัวช่วยแอป macOS นำเข้าตัวช่วย SQLite ที่ใช้ร่วมกัน แทนการเป็นเจ้าของพาธ JSON หรือ SQLite ที่สอง ไฟล์เดิมที่เหลืออยู่identity/device.jsonจะบล็อกการสร้างตัวตน จนกว่า doctor จะนำเข้าไฟล์นั้นไปยัง SQLite ซึ่งตรงกับเกตเริ่มต้นของ TypeScript และ Android. - ตัวตนอุปกรณ์ Android ใช้วัสดุคีย์ที่เข้ากันได้กับ TypeScript ชุดเดียวกัน
ซึ่งเก็บอยู่ในแถวแบบมีชนิด
state/openclaw.sqlite#table/device_identitiesมันจะไม่ อ่านหรือเขียนopenclaw/identity/device.json; ไฟล์เดิมที่เหลืออยู่จะบล็อก การเริ่มต้นจนกว่า doctor จะนำเข้าไฟล์นั้นไปยัง SQLite. - โทเค็นการยืนยันตัวตนอุปกรณ์ Android ที่แคชไว้ยังใช้แถวแบบมีชนิด
state/openclaw.sqlite#table/device_auth_tokensและใช้ซีแมนติกโทเค็น version-1 เดียวกับ TypeScript และ Swift รันไทม์จะไม่อ่านคีย์ความเข้ากันได้SecurePrefsgateway.deviceToken*อีกต่อไป; คีย์เหล่านั้นเป็นของตรรกะการย้ายข้อมูล/doctor เท่านั้น. - ประวัติแพ็กเกจล่าสุดของการแจ้งเตือน Android ใช้แถวแบบมีชนิด
android_notification_recent_packagesรันไทม์จะไม่ย้ายข้อมูลหรือ อ่านคีย์ CSV ของ SharedPreferences แบบเก่าอีกต่อไป. - การสร้างตัวตนอุปกรณ์จะล้มเหลวแบบปิดเมื่อมี
identity/device.jsonเดิม อยู่ เมื่อแถวตัวตนใน SQLite ไม่ถูกต้อง หรือเมื่อเปิดที่เก็บตัวตน SQLite ไม่ได้ doctor จะนำเข้าและลบไฟล์นั้นก่อน ดังนั้นการเริ่มต้นรันไทม์ จึงไม่สามารถหมุนเวียนตัวตนการจับคู่แบบเงียบ ๆ ก่อนการย้ายข้อมูลได้. - การเลือกตัวตนอุปกรณ์เป็นคีย์แถว SQLite ไม่ใช่ตัวระบุตำแหน่งไฟล์ JSON การทดสอบ
และตัวช่วย Gateway ส่งคีย์ตัวตนที่ชัดเจน; มีเพียงการย้ายข้อมูลของ doctor และ
เกตเริ่มต้นแบบล้มเหลวปิดเท่านั้นที่รู้ชื่อไฟล์
identity/device.jsonที่เลิกใช้แล้ว. - ความเข้ากันได้ของการรีเซ็ตเซสชันตอนนี้อยู่ในการย้ายข้อมูลคอนฟิกของ doctor:
session.idleMinutesถูกย้ายไปยังsession.reset.idleMinutes,session.resetByType.dmถูกย้ายไปยังsession.resetByType.directและนโยบายรีเซ็ตของ รันไทม์จะอ่านเฉพาะคีย์รีเซ็ตมาตรฐานเท่านั้น. - ความเข้ากันได้ของคอนฟิกเดิมตอนนี้อยู่ภายใต้
src/commands/doctor/การตรวจสอบreadConfigFileSnapshot()ปกติจะไม่นำเข้าตัวตรวจจับเดิมของ doctor หรือใส่คำอธิบายประเด็นเดิม;runDoctorConfigPreflight()เพิ่มประเด็นเหล่านั้นสำหรับ การซ่อมแซม/รายงานของ doctor โฟลว์คอนฟิก doctor นำเข้าsrc/commands/doctor/legacy-config.tsและการซ่อมแซม profile-id ของ OAuth เก่าอยู่ ภายใต้src/commands/doctor/legacy/oauth-profile-ids.ts. - คำสั่งที่ไม่ใช่ doctor จะไม่เรียกใช้การซ่อมแซมคอนฟิกเดิมโดยอัตโนมัติ ตัวอย่างเช่น
openclaw update --channelตอนนี้จะล้มเหลวเมื่อพบคอนฟิกเดิมที่ไม่ถูกต้องและขอให้ ผู้ใช้เรียกใช้ doctor แทนการนำเข้าโค้ดย้ายข้อมูลของ doctor แบบเงียบ ๆ. - Web push, APNs, Voice Wake, การตรวจสอบอัปเดต และสุขภาพคอนฟิกตอนนี้ใช้ตาราง SQLite ที่ใช้ร่วมกันแบบมีชนิด สำหรับการสมัครรับ, คีย์ VAPID, การลงทะเบียน Node, แถวทริกเกอร์, แถวการกำหนดเส้นทาง, สถานะการแจ้งเตือนอัปเดต และรายการสุขภาพคอนฟิก แทน บล็อบ JSON ทึบทั้งก้อน ตอนนี้การเขียนสแนปชอต Web push และ APNs จะกระทบยอด การสมัครรับ/การลงทะเบียนตามคีย์หลักแทนการล้างตาราง; สุขภาพคอนฟิกทำแบบเดียวกันตามพาธคอนฟิก. โมดูลรันไทม์ของรายการเหล่านี้แยกตัวอ่าน/ตัวเขียนสแนปชอต SQLite ออกจาก ตัวช่วยนำเข้า JSON เดิมที่ใช้เฉพาะ doctor.
- คอนฟิกโฮสต์ Node ตอนนี้ใช้แถวซิงเกิลตันแบบมีชนิดในฐานข้อมูล SQLite ที่ใช้ร่วมกัน;
doctor นำเข้าไฟล์
node.jsonเก่าก่อนการใช้งานรันไทม์ปกติ. - การจับคู่อุปกรณ์/Node, การจับคู่ช่องทาง, allowlist ของช่องทาง และสถานะบูตสแตรป
ตอนนี้ใช้แถว SQLite แบบมีชนิดแทนบล็อบ JSON ทึบทั้งก้อน การอนุมัติการผูก Plugin
และสถานะงาน cron ใช้การแยกแบบเดียวกัน: โมดูลรันไทม์เปิดเผย
การดำเนินการที่หนุนด้วย SQLite และตัวช่วยสแนปชอตที่เป็นกลาง และการเขียนสแนปชอตการจับคู่/บูตสแตรป
รวมถึงการอนุมัติการผูก Plugin จะกระทบยอดแถวตามคีย์หลัก
แทนการตัดตารางทิ้ง ขณะที่ doctor นำเข้า/ลบไฟล์ JSON เก่าผ่าน
โมดูล
src/commands/doctor/legacy/*. - ระเบียน Plugin ที่ติดตั้งแล้วตอนนี้อยู่ในดัชนี Plugin ที่ติดตั้งแล้วของ SQLite.
การอ่าน/เขียนคอนฟิกรันไทม์จะไม่ย้ายข้อมูลหรือคงข้อมูล authored-config เก่า
plugins.installsอีกต่อไป; doctor นำเข้ารูปแบบคอนฟิกเดิมนั้น ไปยัง SQLite ก่อนการใช้งานรันไทม์ปกติ. - สแนปชอตกู้คืนข้อมูลประจำตัว QQBot ตอนนี้อยู่ในสถานะ Plugin ของ SQLite ภายใต้
qqbot/credential-backupsรันไทม์จะไม่เขียนqqbot/data/credential-backup*.jsonอีกต่อไป; doctor นำเข้าและลบไฟล์สำรองเดิมเหล่านั้น พร้อมกับอินพุตสถานะ QQBot อื่น ๆ. - การวางแผนรีโหลด Gateway เปรียบเทียบสแนปชอตดัชนี Plugin ที่ติดตั้งแล้วของ SQLite ภายใต้
เนมสเปซ diff ภายใน
installedPluginIndex.installRecords.*การตัดสินใจรีโหลดของรันไทม์ จะไม่ห่อแถวเหล่านั้นไว้ในออบเจ็กต์คอนฟิกplugins.installsปลอมอีกต่อไป. - การอัปเกรดข้อมูลประจำตัวของบัญชี Matrix แบบมีชื่อจะไม่เกิดขึ้นระหว่างการอ่านของรันไทม์
อีกต่อไป doctor เป็นเจ้าของการเปลี่ยนชื่อ
credentials/matrix/credentials.jsonระดับบนสุดแบบเก่า เมื่อสามารถแก้บัญชี Matrix เดียว/ค่าเริ่มต้นได้. - โมดูลรันไทม์การจับคู่หลักและ cron จะไม่ส่งออกตัวสร้างพาธ JSON เดิมอีกต่อไป
โมดูลเดิมที่ doctor เป็นเจ้าของสร้างพาธต้นทาง
pending.json,paired.json,bootstrap.jsonและcron/jobs.jsonสำหรับการทดสอบนำเข้าและ การย้ายข้อมูลเท่านั้น การปรับรูปแบบงาน cron เดิมให้เป็นมาตรฐานและการนำเข้า run-log ของ cron อยู่ภายใต้src/commands/doctor/legacy/cron*.ts. src/commands/doctor/legacy/runtime-state.tsนำเข้าไฟล์สถานะ JSON เดิม รวมถึงคอนฟิกโฮสต์ Node ไปยัง SQLite จาก doctor ตัวนำเข้าไฟล์เดิมใหม่ ยังคงอยู่ภายใต้src/commands/doctor/legacy/.src/commands/doctor/state-migrations.tsนำเข้าsessions.jsonเดิมและ ทรานสคริปต์*.jsonlโดยตรงไปยัง SQLite และลบแหล่งที่สำเร็จ มัน จะไม่จัดสเตจทรานสคริปต์เดิมระดับรูตผ่านagents/<agentId>/sessions/*.jsonlหรือสร้างเป้าหมาย JSONL มาตรฐานก่อน การนำเข้าอีกต่อไป.- การตรวจสอบความสมบูรณ์ของสถานะโดย doctor จะไม่สแกนไดเรกทอรีเซสชันเดิมหรือ เสนอการลบ JSONL กำพร้าอีกต่อไป ไฟล์ทรานสคริปต์เดิมเป็นอินพุตการย้ายข้อมูล เท่านั้น และขั้นตอนการย้ายข้อมูลเป็นเจ้าของการนำเข้าและการลบแหล่งที่มา.
- การนำเข้ารีจิสทรี sandbox เดิมอยู่ภายใต้
src/commands/doctor/legacy/sandbox-registry.ts; การอ่านและเขียนรีจิสทรี sandbox ที่ใช้งานอยู่ยังคงเป็น SQLite เท่านั้น. - การซ่อมแซมสุขภาพ/การนำเข้าทรานสคริปต์เซสชันเดิมอยู่ภายใต้
src/commands/doctor/legacy/session-transcript-health.ts; โมดูลคำสั่งรันไทม์ จะไม่พกโค้ดแยกวิเคราะห์ทรานสคริปต์ JSONL หรือซ่อมแซม active-branch อีกต่อไป.
ไฮไลต์การรวมและการลบที่เสร็จสมบูรณ์:
- สถานะ Plugin ตอนนี้ใช้ฐานข้อมูล
state/openclaw.sqliteที่ใช้ร่วมกัน ตัวนำเข้า sidecar เดิมของplugin-state/state.sqliteแบบเฉพาะ branch ถูกลบออกแล้วเพราะ เลย์เอาต์ SQLite นั้นไม่เคยถูกปล่อยใช้งาน ตัวช่วย probe/test รายงานdatabasePathที่ใช้ร่วมกันแทนการเปิดเผยพาธ SQLite เฉพาะสถานะ Plugin - ตารางรันไทม์ของ Task และ Task Flow ตอนนี้อยู่ในฐานข้อมูล
state/openclaw.sqliteที่ใช้ร่วมกันแทนtasks/runs.sqliteและtasks/flows/registry.sqlite; ตัวนำเข้า sidecar เดิมถูกลบออกด้วย เหตุผลเดียวกันว่าเลย์เอาต์นั้นไม่เคยถูกปล่อยใช้งาน src/config/sessions/store.tsไม่ต้องใช้storePathอีกต่อไปสำหรับ เมทาดาทาขาเข้า การอัปเดต route หรือการอ่าน updated-at การคงอยู่ของคำสั่ง การล้างข้อมูล session ของ CLI ความลึกของ subagent การ override การยืนยันตัวตน และอัตลักษณ์ session ของ transcript ใช้ API แถว agent/session การเขียนถูกนำไปใช้เป็นแพตช์แถว SQLite พร้อมการลองใหม่เมื่อเกิดความขัดแย้งแบบ optimistic- การระบุเป้าหมายของ session ตอนนี้เปิดเผยเป้าหมายฐานข้อมูลต่อ agent ไม่ใช่พาธ
sessions.jsonแบบเดิม Shared gateway, เมทาดาทา ACP, การซ่อมแซม route ของ doctor และopenclaw sessionsจะไล่รายการagent_databasesรวมถึง agent ที่กำหนดค่าไว้ - การกำหนด route ของ session ใน Gateway ตอนนี้ใช้
resolveGatewaySessionDatabaseTarget; เป้าหมายที่คืนกลับมาจะมีdatabasePathและคีย์แถว SQLite ผู้สมัครแทน พาธไฟล์ session-store แบบเดิม - ชนิดรันไทม์ของ session ช่องทางตอนนี้เปิดเผย
{agentId, sessionKey}สำหรับ การอ่าน updated-at, เมทาดาทาขาเข้า และการอัปเดต last-route ชนิดความเข้ากันได้เดิมsaveSessionStore(storePath, store)ถูกลบแล้ว - พื้นผิวของรันไทม์ Plugin, extension API และ barrel ของ
config/sessionsตอนนี้นำ โค้ด Plugin ไปใช้ตัวช่วยแถว session ที่รองรับด้วย SQLite export ความเข้ากันได้ของไลบรารีราก (loadSessionStore,saveSessionStore,resolveStorePath) ยังคงอยู่เป็น shim ที่เลิกใช้แล้วสำหรับผู้ใช้งานเดิม ตัวช่วยเดิมresolveLegacySessionStorePathถูกลบแล้ว; การสร้างพาธsessions.jsonแบบเดิม ตอนนี้อยู่เฉพาะใน migration และ fixture ทดสอบ src/config/sessions/session-entries.sqlite.tsตอนนี้จัดเก็บรายการ session แบบ canonical ในฐานข้อมูลต่อ agent และรองรับแพตช์ read/upsert/delete ระดับแถว runtime upsert/patch/delete จะไม่สแกนหาตัวแปรต่างกรณีอักษรหรือ ตัดคีย์ alias เดิมอีกต่อไป; doctor เป็นเจ้าของการ canonicalize ตัวช่วยนำเข้า JSON แบบ standalone ถูกลบแล้ว และ migration จะ merge upsert แถวที่ใหม่กว่า แทนการแทนที่ตาราง session ทั้งหมด ตัวช่วย read/list/load สาธารณะ project เมทาดาทา session hot จากแถวsessionsและconversationsที่มีชนิดกำกับ;entry_jsonเป็นเงาความเข้ากันได้/debug และอาจ stale หรือไม่ถูกต้อง ได้โดยไม่สูญเสียอัตลักษณ์ session หรือบริบทการส่งมอบที่มีชนิดกำกับsrc/config/sessions/delivery-info.tsตอนนี้ระบุบริบทการส่งมอบจากแถวsessions+conversations+session_conversationsแบบมีชนิดกำกับต่อ agent มันจะไม่สร้างอัตลักษณ์การส่งมอบของ runtime ใหม่จากsession_entries.entry_jsonอีกต่อไป; แถว conversation แบบมีชนิดกำกับที่หายไปเป็นปัญหา migration/repair ของ doctor ไม่ใช่ fallback ของ runtime- การตัดสินใจรีเซ็ต stored-session ตอนนี้ให้ความสำคัญกับเมทาดาทา
sessions.session_scope,sessions.chat_typeและsessions.channelแบบมีชนิดกำกับ การ parsesessionKeyยังคงมีเฉพาะสำหรับ suffix ของ thread/topic ที่ชัดเจนบนเป้าหมายคำสั่ง; การจัดประเภทการรีเซ็ต แบบ group เทียบกับ direct จะไม่มาจากรูปทรงคีย์อีกต่อไป - การจัดประเภทการแสดงรายการ/สถานะ session ตอนนี้ใช้เมทาดาทา chat ที่มีชนิดกำกับและ
ชนิด session ของ gateway มันจะไม่ถือว่า substring
:group:หรือ:channel:ภายในsession_keyเป็นความจริงถาวรของ group/direct อีกต่อไป - การเลือกนโยบาย silent-reply ตอนนี้ใช้เฉพาะชนิด conversation หรือเมทาดาทา surface ที่ชัดเจน
มันจะไม่เดานโยบาย direct/group จาก substring ของ
session_keyอีกต่อไป - การระบุโมเดลแสดงผลของ session ตอนนี้รับ id ของ agent จากเป้าหมายฐานข้อมูล session
SQLite แทนการแยกออกมาจาก
session_key - การเติมข้อมูลเป้าหมายประกาศ agent-to-agent ตอนนี้ใช้เฉพาะ
deliveryContextจากsessions.listแบบมีชนิดกำกับ มันจะไม่กู้คืน route ของ channel/account/thread จากoriginเดิม ฟิลด์last*ที่ mirror ไว้ หรือรูปทรงsession_keyอีกต่อไป - การปฏิเสธเป้าหมาย thread ของ
sessions_sendตอนนี้อ่านเมทาดาทา routing ของ SQLite ที่มีชนิดกำกับ มันจะไม่ปฏิเสธหรือยอมรับเป้าหมายด้วยการ parse suffix ของ thread ออกจากคีย์เป้าหมายอีกต่อไป - การตรวจสอบนโยบายเครื่องมือแบบ group-scoped ตอนนี้อ่าน routing conversation ของ SQLite
ที่มีชนิดกำกับสำหรับ session ปัจจุบันหรือ session ที่ spawn ขึ้น มันจะไม่เชื่อถืออัตลักษณ์ group/channel
ด้วยการถอดรหัส
sessionKeyอีกต่อไป; id ของ group ที่ caller ให้มาจะถูกทิ้งเมื่อ ไม่มีแถว session แบบมีชนิดกำกับรับรอง - การจับคู่ override โมเดลของ channel ตอนนี้ใช้เมทาดาทา group และ parent
conversation ที่ชัดเจน มันจะไม่ถอดรหัส id ของ parent conversation จาก
parentSessionKeyอีกต่อไป - การสืบทอด stored model override ตอนนี้ต้องมี parent session key ที่ชัดเจน
จากบริบท session แบบมีชนิดกำกับ มันจะไม่ derive parent overrides จาก
suffix
:thread:หรือ:topic:ในsessionKeyอีกต่อไป - wrapper thread-info ของ session แบบเดิมและ parser thread ของ loaded-plugin ถูกลบแล้ว;
ไม่มีโค้ด runtime ใด import
config/sessions/thread-info - ตัวช่วย conversation ของ channel จะไม่เปิดเผย bridge สำหรับการ parse full-session-key อีกต่อไป
core ยังคง normalize id conversation ดิบที่ provider เป็นเจ้าของผ่าน
resolveSessionConversation(...)แต่จะไม่สร้างข้อเท็จจริง route ใหม่ จากsessionKey - การส่งมอบ completion, นโยบาย send และการบำรุงรักษา task จะไม่ derive ชนิด chat
จากรูปทรง
session_keyอีกต่อไป parser คีย์ chat-type เดิมถูกลบแล้ว; พาธเหล่านี้ต้องใช้เมทาดาทา session แบบมีชนิดกำกับ บริบทการส่งมอบแบบมีชนิดกำกับ หรือ ศัพท์เป้าหมายการส่งมอบที่ชัดเจน - รายการ/สถานะ session, diagnostics, การผูกบัญชี approval, การกรอง TUI heartbeat
และสรุปการใช้งานจะไม่ขุด
SessionEntry.originเพื่อหา routing provider/account/thread/display อีกต่อไป การอ่านoriginใน runtime ที่เหลืออยู่มีเพียงแนวคิดที่ไม่ใช่ session หรือวัตถุการส่งมอบของ turn ปัจจุบัน - การค้นหา native conversation ของ approval-request ตอนนี้อ่านแถว routing session
แบบมีชนิดกำกับต่อ agent มันจะไม่ parse อัตลักษณ์ conversation ของ channel/group/thread
จาก
sessionKeyอีกต่อไป; เมทาดาทาแบบมีชนิดกำกับที่หายไปเป็นปัญหา migration/repair - payload เหตุการณ์ session changed/chat/session ของ Gateway จะไม่ echo
SessionEntry.originหรือเงา routelast*อีกต่อไป; client จะได้รับchannel,chatTypeและdeliveryContextแบบมีชนิดกำกับ - การระบุการส่งมอบ Heartbeat ตอนนี้รับ
deliveryContextของ SQLite แบบมีชนิดกำกับได้โดยตรง และรันไทม์ heartbeat ส่งแถวการส่งมอบ session ต่อ agent แทนการพึ่งพาเงาsession_entriesความเข้ากันได้สำหรับ routing ปัจจุบัน - การระบุเป้าหมายการส่งมอบ agent แยกของ Cron ก็เติม route ปัจจุบัน จากแถวการส่งมอบ session แบบมีชนิดกำกับต่อ agent ก่อน fallback ไปยัง payload รายการความเข้ากันได้เช่นกัน
- การระบุ origin ของประกาศ subagent ตอนนี้ส่งต่อบริบทการส่งมอบ requester-session
แบบมีชนิดกำกับผ่าน
loadRequesterSessionEntryและให้ความสำคัญกับแถวนั้นเหนือ เงาlast*/deliveryContextความเข้ากันได้ - การอัปเดตเมทาดาทา session ขาเข้าตอนนี้ merge กับแถวการส่งมอบต่อ agent
แบบมีชนิดกำกับก่อน; ฟิลด์การส่งมอบ
SessionEntryเดิมเป็นเพียง fallback เมื่อไม่มีแถว conversation แบบมีชนิดกำกับ - การแยกข้อมูลการส่งมอบ restart/update ตอนนี้ให้
threadIdของการส่งมอบ SQLite แบบมีชนิดกำกับชนะ fragment topic/thread ที่ parse จากsessionKey; การ parse เป็นเพียง fallback สำหรับคีย์แบบ thread-shaped เดิม - id ของ channel ในบริบท hook agent ตอนนี้ให้ความสำคัญกับอัตลักษณ์ conversation ของ SQLite
แบบมีชนิดกำกับ จากนั้นเป็นเมทาดาทาข้อความที่ชัดเจน มันจะไม่ parse fragment provider/group/channel
จาก
sessionKeyอีกต่อไป - การสืบทอด external-route ของ Gateway
chat.sendตอนนี้อ่านเมทาดาทา routing session ของ SQLite แบบมีชนิดกำกับแทนการอนุมาน scope channel/direct/group จาก ชิ้นส่วนsessionKeysession แบบ channel-scoped จะสืบทอดเฉพาะเมื่อ channel ของ session แบบมีชนิดกำกับและชนิด chat ตรงกับบริบทการส่งมอบที่จัดเก็บไว้; session shared-main ยังคงใช้กฎ CLI/no-client-metadata ที่เข้มงวดกว่า - wake ของ restart-sentinel และ routing การ continuation ตอนนี้อ่านแถว delivery/routing ของ SQLite แบบมีชนิดกำกับก่อน queue heartbeat wake หรือ continuation agent-turn ที่ routed มันจะไม่สร้างบริบทการส่งมอบใหม่จากเงา JSON ของ session-entry อีกต่อไป
- การระบุบริบท Gateway
tools.effectiveตอนนี้อ่านแถว delivery/routing ของ SQLite แบบมีชนิดกำกับสำหรับ input provider, account, target, thread และ reply-mode มันจะไม่กู้คืนฟิลด์ routing hot เหล่านั้นจากเงา origin ของsession_entries.entry_jsonที่ stale อีกต่อไป - routing ของ realtime voice consult ตอนนี้ระบุ parent/call delivery จากแถว session SQLite
แบบมีชนิดกำกับต่อ agent มันจะไม่ fallback ไปยังเงา
SessionEntry.deliveryContextความเข้ากันได้เมื่อเลือก route ข้อความ agent แบบ embedded - relay heartbeat ของ ACP spawn และ routing parent-stream ตอนนี้อ่าน parent delivery จากแถว session SQLite แบบมีชนิดกำกับ มันจะไม่สร้างบริบท parent delivery ใหม่จากเงา session-entry ความเข้ากันได้อีกต่อไป
- การคง route การส่งมอบ session ตอนนี้ตามเมทาดาทา chat แบบมีชนิดกำกับและ
คอลัมน์การส่งมอบที่คงอยู่ มันจะไม่แยก hint ของ channel, marker direct/main
หรือรูปทรง thread จาก
sessionKeyอีกต่อไป; route webchat ภายในจะ สืบทอดเป้าหมายภายนอกเฉพาะเมื่อ SQLite มีอัตลักษณ์ delivery แบบมีชนิดกำกับ/คงอยู่ สำหรับ session อยู่แล้ว - การแยกข้อมูลการส่งมอบ session แบบ generic ตอนนี้อ่านเฉพาะแถวการส่งมอบ session SQLite แบบมีชนิดกำกับที่ตรงกันเท่านั้น มันจะไม่ parse suffix thread/topic หรือ fallback จากคีย์แบบ thread-shaped ไปยังคีย์ session ฐานอีกต่อไป
- reply dispatch, การกู้คืน restart sentinel และ routing realtime voice consult ตอนนี้ใช้แถว session/conversation ของ SQLite แบบมีชนิดกำกับที่ตรงกันสำหรับ routing thread มันจะไม่กู้คืน id thread หรือบริบท delivery ของ base-session ด้วยการ parse session key แบบ thread-shaped อีกต่อไป
- การจำกัดประวัติ Embedded PI ตอนนี้ใช้ projection routing session ของ SQLite
แบบมีชนิดกำกับ (
sessions+conversationsหลัก) สำหรับ provider, ชนิด chat และอัตลักษณ์ peer มันจะไม่ parse provider, DM, group หรือรูปทรง thread ออกจากsessionKeyอีกต่อไป - การอนุมานการส่งมอบเครื่องมือ Cron ตอนนี้ใช้เฉพาะการส่งมอบที่ชัดเจนหรือบริบทการส่งมอบ
แบบมีชนิดกำกับปัจจุบันเท่านั้น มันจะไม่ถอดรหัสเป้าหมาย channel, peer, account หรือ thread
จาก
agentSessionKeyอีกต่อไป - แถว session ของ runtime จะไม่พก alias route เดิม
lastProviderอีกต่อไป ตัวช่วยและการทดสอบใช้ฟิลด์lastChannelและdeliveryContextแบบมีชนิดกำกับ; migration ของ doctor เป็นที่เดียวที่ควรแปล alias route เก่าหรือเงาoriginที่คงอยู่ - เหตุการณ์ transcript, แถว VFS และแถว artifact ของเครื่องมือตอนนี้เขียนไปยังฐานข้อมูลต่อ agent ตาราง mapping transcript-file ระดับ global ที่ไม่เคยถูกปล่อยใช้งานถูกลบแล้ว; doctor บันทึกพาธ source เดิมในแถว migration ที่คงทนแทน
- การค้นหา transcript ของ runtime จะไม่สแกน byte offset ของ JSONL หรือ probe ไฟล์ transcript เดิมอีกต่อไป พาธ chat/media/history ของ Gateway อ่านแถว transcript จาก SQLite; session JSONL ตอนนี้เป็นเพียง input เดิมของ doctor ไม่ใช่ state ของ runtime หรือรูปแบบ export
- ความสัมพันธ์ parent และ branch ของ transcript ใช้เมทาดาทา
parentTranscriptScope: {agentId, sessionId}แบบมีโครงสร้างใน header transcript ของ SQLite ไม่ใช่สตริง locator แบบ path-likeagent-db:...transcript_events... - contract ของ transcript manager จะไม่เปิดเผย constructor แบบ implicit persisted
create(cwd)หรือcontinueRecent(cwd)อีกต่อไป transcript manager แบบ persisted จะถูกเปิดด้วย scope{agentId, sessionId}ที่ชัดเจน; มีเพียง manager ในหน่วยความจำเท่านั้นที่ยังไม่ต้องมี scope สำหรับการทดสอบและ transform transcript ล้วน - API store transcript ของ runtime ระบุ scope SQLite ไม่ใช่พาธ filesystem ตัวช่วย
resolve...ForPathเดิมและตัวเลือกเขียนtranscriptPathที่ไม่ได้ใช้ ถูกลบออกจาก caller ของ runtime แล้ว - การระบุ session ของ runtime ตอนนี้ใช้
{agentId, sessionId}และต้องไม่ derive สตริงsqlite-transcript://<agent>/<session>สำหรับ boundary ภายนอก พาธ JSONL แบบ absolute เดิมเป็น input migration ของ doctor เท่านั้น - ระเบียน direct-bridge ของ native hook relay ตอนนี้อยู่ในแถว
native_hook_relay_bridgesที่มีชนิดกำกับและใช้ร่วมกัน keyed by relay id runtime จะไม่เขียน registry JSON ใน/tmpหรือระเบียน generic ทึบสำหรับระเบียน bridge อายุสั้นเหล่านั้นอีกต่อไป runEmbeddedPiAgent(...)ไม่มีพารามิเตอร์ transcript-locator อีกต่อไป ตัวบรรยาย worker ที่เตรียมไว้จะไม่รวมตัวระบุตำแหน่ง transcript อีกต่อไป สถานะเซสชันของรันไทม์ และรันติดตามผลที่เข้าคิวจะพก{agentId, sessionId}แทน handle ของ transcript ที่อนุมานมา- Embedded compaction ตอนนี้รับขอบเขต SQLite จาก
agentIdและsessionIdHook ของ Compaction, การเรียก context-engine, การมอบหมายจาก CLI และการตอบกลับของโปรโตคอล ต้องไม่รับ handle ที่อนุมานมาในรูปsqlite-transcript://...โค้ด export/debug สามารถสร้าง artifact ผู้ใช้แบบชัดเจนจากแถวได้ แต่จะไม่ให้เส้นทาง export JSONL ของเซสชันแบบทั่วไปหรือป้อนชื่อไฟล์กลับเข้าไปเป็นอัตลักษณ์ ของรันไทม์ /export-sessionอ่านแถว transcript จาก SQLite และเขียนเฉพาะมุมมอง HTML แบบ standalone ที่ร้องขอเท่านั้น Viewer แบบ embedded จะไม่ประกอบหรือ ดาวน์โหลด JSONL ของเซสชันขึ้นใหม่จากแถวเหล่านั้นอีก- การมอบหมาย context-engine จะไม่แยกวิเคราะห์ตัวระบุตำแหน่ง transcript เพื่อกู้คืน
อัตลักษณ์ของ agent อีกต่อไป บริบทรันไทม์ที่เตรียมไว้จะพก
agentIdที่ resolve แล้วเข้าไปใน adapter Compaction ในตัว - การ rewrite transcript และการตัดทอน live tool-result ตอนนี้อ่านและ persist
สถานะ transcript ด้วย
{agentId, sessionId}และไม่อนุมานตัวระบุตำแหน่ง ชั่วคราวสำหรับ payload เหตุการณ์ transcript-update - พื้นผิว helper ของสถานะ transcript จะไม่มี variant แบบอิงตัวระบุตำแหน่ง
readTranscriptState,replaceTranscriptStateEventsหรือpersistTranscriptStateMutationอีกต่อไป ผู้เรียกรันไทม์ต้องใช้ API{agentId, sessionId}การนำเข้า Doctor อ่านไฟล์ legacy ด้วย path ไฟล์ ที่ชัดเจนและเขียนแถว SQLite โดยจะไม่ migrate string ตัวระบุตำแหน่ง - สัญญา session-manager ของรันไทม์จะไม่ expose
open(locator),forkFrom(locator)หรือsetTranscriptLocator(...)อีกต่อไป session manager แบบ persisted เปิดด้วย{agentId, sessionId}เท่านั้น; helper list/fork อยู่บน API session และ checkpoint แบบเน้นแถวแทน facade ของ transcript manager - API reader ของ Gateway transcript เป็นแบบ scope-first โดยรับ
{agentId, sessionId}และไม่ยอมรับตัวระบุตำแหน่ง transcript แบบ positional ที่ อาจกลายเป็นอัตลักษณ์ของรันไทม์โดยไม่ตั้งใจ การแยกวิเคราะห์ตัวระบุตำแหน่ง transcript ที่ active ถูกลบออกแล้ว; path แหล่งที่มา legacy อ่านโดยโค้ดนำเข้า doctor เท่านั้น - เหตุการณ์อัปเดต transcript ก็เป็นแบบ scope-first เช่นกัน
emitSessionTranscriptUpdateจะไม่รับ string ตัวระบุตำแหน่งเปล่าอีกต่อไป และ listener route ด้วย{agentId, sessionId}โดยไม่แยกวิเคราะห์ handle - การ broadcast session-message ของ Gateway resolve session key จากขอบเขต agent/session ไม่ใช่จากตัวระบุตำแหน่ง transcript ตัว resolver/cache จาก transcript-locator ไปเป็น session key แบบเก่าถูกลบแล้ว
- ตัวกรอง SSE ของ session-history ใน Gateway กรอง live update ด้วยขอบเขต agent/session มันจะไม่ canonicalize candidate ของตัวระบุตำแหน่ง transcript, realpath หรืออัตลักษณ์ transcript รูปแบบไฟล์เพื่อใช้ตัดสินว่า stream ควรได้รับ update หรือไม่อีก
- Hook lifecycle ของเซสชันจะไม่อนุมานหรือ expose ตัวระบุตำแหน่ง transcript บน
session_endอีกต่อไป ผู้บริโภค hook จะได้รับsessionId,sessionKey, id ของเซสชันถัดไป และบริบท agent; ไฟล์ transcript ไม่เป็นส่วนหนึ่งของสัญญา lifecycle - Hook reset จะไม่อนุมานหรือ expose ตัวระบุตำแหน่ง transcript เช่นกัน
payload
before_resetพกข้อความ SQLite ที่กู้คืนได้พร้อมเหตุผลการ reset ขณะที่อัตลักษณ์เซสชันยังอยู่ในบริบท hook - การ reset ของ agent harness จะไม่รับตัวระบุตำแหน่ง transcript อีกต่อไป การ dispatch reset
ถูกจำกัดขอบเขตด้วย
sessionId/sessionKeyพร้อมเหตุผล - ชนิดเซสชันของส่วนขยาย agent จะไม่ expose
transcriptLocatorอีกต่อไป; extension ควรใช้บริบทเซสชันและ API รันไทม์แทนการเอื้อมไปหาอัตลักษณ์ transcript รูปแบบไฟล์ - Hook Compaction ของ Plugin จะไม่ expose ตัวระบุตำแหน่ง transcript อีกต่อไป บริบท hook พกอัตลักษณ์เซสชันอยู่แล้ว และการอ่าน transcript ต้องผ่าน API ที่รับรู้ขอบเขต SQLite แทน handle รูปแบบไฟล์
- Hook
before_agent_finalizeจะไม่ exposetranscriptPathอีกต่อไป รวมถึง payload relay ของ hook native ด้วย Hook finalization ใช้เฉพาะบริบทเซสชัน - การตอบกลับ reset ของ Gateway จะไม่สังเคราะห์ตัวระบุตำแหน่ง transcript บน entry ที่ส่งคืนอีกต่อไป การ reset สร้างแถว transcript SQLite, ส่งคืน entry เซสชันสะอาด และปล่อยให้การเข้าถึง transcript เป็นหน้าที่ของ reader ที่รับรู้ขอบเขต
- ผลลัพธ์ embedded run และ Compaction จะไม่เผยตัวระบุตำแหน่ง transcript สำหรับ
การคิดบัญชีเซสชันอีกต่อไป Automatic Compaction อัปเดตเฉพาะ
sessionIdที่ active, counter ของ Compaction และ metadata token - ผลลัพธ์ embedded attempt จะไม่ส่งคืน
transcriptLocatorUsedอีกต่อไป และ ผลลัพธ์compact()ของ context-engine จะไม่ส่งคืนตัวระบุตำแหน่ง transcript อีกต่อไป ลูป retry ของรันไทม์ยอมรับเฉพาะsessionIdตัวถัดไป - ผลลัพธ์ append transcript ของ delivery-mirror จะไม่ส่งคืนตัวระบุตำแหน่ง
transcript อีกต่อไป ผู้เรียกจะได้รับ
messageIdที่ append แล้ว; สัญญาณอัปเดต transcript ใช้ขอบเขต SQLite - Helper fork ของ parent-session ส่งคืนเฉพาะ
sessionIdที่ fork แล้ว การเตรียม subagent ส่งขอบเขต agent/session ลูกไปยัง engine - พารามิเตอร์ CLI runner และการ reseed ประวัติจะไม่รับตัวระบุตำแหน่ง transcript อีกต่อไป
การอ่านประวัติของ CLI resolve ขอบเขต transcript SQLite จาก
{agentId, sessionId}และบริบท session key - Fixture ทดสอบ CLI และ embedded-runner ตอนนี้ seed และอ่านแถว transcript SQLite
ด้วย session id แทนการแกล้งทำว่าเซสชัน active เป็นไฟล์
*.jsonlหรือ ส่ง stringsqlite-transcript://...ผ่านพารามิเตอร์รันไทม์ - เหตุการณ์ guard ของ session tool-result emit จากขอบเขตเซสชันที่รู้จัก แม้เมื่อ
manager ในหน่วยความจำไม่มีตัวระบุตำแหน่งที่อนุมานมา การทดสอบของมันจะไม่ปลอมไฟล์
transcript
/tmp/*.jsonlที่ active อีกต่อไป - Helper BTW และ compaction-checkpoint ตอนนี้อ่านและ fork แถว transcript ด้วย ขอบเขต SQLite ตอนนี้ metadata checkpoint เก็บเฉพาะ session id และ leaf/entry id เท่านั้น; ตัวระบุตำแหน่งที่อนุมานมาจะไม่ถูกเขียนลงใน payload checkpoint อีก
- การ lookup transcript-key ของ Gateway ใช้ขอบเขต transcript SQLite ที่ขอบเขตโปรโตคอล และจะไม่ realpath หรือ stat ชื่อไฟล์ transcript อีกต่อไป
- การหมุน transcript ของ Automatic Compaction เขียนแถว transcript ตัวถัดไป ผ่าน SQLite transcript store โดยตรง แถวเซสชันเก็บเฉพาะอัตลักษณ์เซสชัน ตัวถัดไป ไม่ใช่ path JSONL ถาวรหรือตัวระบุตำแหน่งที่ persist ไว้
- Embedded context-engine Compaction ใช้ helper การหมุน transcript ที่ตั้งชื่อด้วย SQLite การทดสอบการหมุนจะไม่สร้าง path JSONL ตัวถัดไปหรือจำลองเซสชัน active เป็นไฟล์อีก
- การเก็บรักษารูปภาพขาออกแบบ managed ใช้ key ของแคช transcript-message จาก stats ของ transcript SQLite แทนการเรียก stat ของ filesystem
- lock เซสชันรันไทม์และ lane doctor legacy
.jsonl.lockแบบ standalone ถูกลบแล้ว - barrel รันไทม์ของ Microsoft Teams และ plugin SDK สาธารณะจะไม่ re-export helper file-lock เก่าอีกต่อไป; path สถานะ Plugin แบบ durable รองรับด้วย SQLite
- การ prune เซสชันตามอายุ/จำนวนและการ cleanup เซสชันแบบ explicit ถูกลบแล้ว Doctor เป็นเจ้าของการนำเข้า legacy; เซสชันที่ stale จะถูก reset หรือลบอย่างชัดเจน
- การตรวจสอบ integrity ของ Doctor จะไม่นับไฟล์ JSONL legacy เป็น transcript active ที่ valid สำหรับแถวเซสชัน SQLite อีกต่อไป สุขภาพของ transcript active เป็น SQLite-only; ไฟล์ JSONL legacy จะถูกรายงานเป็น input สำหรับ migration/orphan-cleanup
- Doctor จะไม่ถือว่า
agents/<agent>/sessions/เป็นสถานะรันไทม์ที่จำเป็น อีกต่อไป มันจะ scan directory นั้นเฉพาะเมื่อมีอยู่แล้ว ในฐานะ input สำหรับการนำเข้า legacy หรือ orphan-cleanup - Gateway
sessions.resolve, path session patch/reset/compact, การ spawn subagent, fast abort, metadata ACP, เซสชันที่แยก Heartbeat และการ patch TUI จะไม่ migrate หรือ prune session key legacy เป็น side effect ของงานรันไทม์ ปกติอีกต่อไป - การ resolve เซสชันของคำสั่ง CLI ตอนนี้ส่งคืน
agentIdเจ้าของแทนstorePathและจะไม่คัดลอกแถว main-session legacy ระหว่างการ resolve--toหรือ--session-idตามปกติอีกต่อไป การ canonicalize main-row legacy เป็นของ doctor เท่านั้น - การ resolve ความลึก subagent ของรันไทม์จะไม่อ่าน
sessions.jsonหรือ store เซสชัน JSON5 อีกต่อไป มันอ่านsession_entriesของ SQLite ด้วย agent id และ metadata depth/session legacy สามารถเข้ามาได้ผ่าน path นำเข้าของ doctor เท่านั้น - override เซสชันของ auth profile persist ผ่าน upsert แถว
{agentId, sessionKey}โดยตรง แทนการ lazy-load รันไทม์ session-store รูปแบบไฟล์ - gating แบบ verbose ของ auto-reply และ helper อัปเดตเซสชัน ตอนนี้อ่าน/upsert แถว เซสชัน SQLite ด้วยอัตลักษณ์เซสชัน และไม่ต้องใช้ path store legacy ก่อนแตะสถานะแถวที่ persist อีกต่อไป
- Helper metadata เซสชันของ command-run ตอนนี้ใช้ชื่อและ module path แบบเน้น entry;
พื้นผิว helper คำสั่ง
session-storeแบบเก่าถูกลบแล้ว - การ seed bootstrap header และการ harden ขอบเขต manual Compaction ตอนนี้ mutate
แถว transcript SQLite โดยตรง ผู้เรียกรันไทม์ส่งอัตลักษณ์เซสชัน ไม่ใช่
path
.jsonlที่เขียนได้ - การ replay การหมุนเซสชันแบบเงียบคัดลอก turn ล่าสุดของ user/assistant ด้วย
{agentId, sessionId}จากแถว transcript SQLite มันจะไม่รับตัวระบุตำแหน่ง transcript ต้นทางหรือปลายทางอีกต่อไป - แถวเซสชันรันไทม์ใหม่จะไม่เก็บตัวระบุตำแหน่ง transcript อีกต่อไป ผู้เรียกใช้
{agentId, sessionId}โดยตรง; คำสั่ง export/debug สามารถเลือกชื่อไฟล์ output เมื่อ materialize แถวได้ - การเริ่มเซสชัน transcript แบบ persisted ใหม่ ตอนนี้จะเปิดแถว SQLite ด้วย ขอบเขตเสมอ session manager จะไม่ reuse path หรือตัวระบุตำแหน่ง transcript ยุคไฟล์ก่อนหน้าเป็นอัตลักษณ์สำหรับเซสชันใหม่อีกต่อไป
- เซสชัน transcript แบบ persisted ใช้ API ที่ชัดเจน
openTranscriptSessionManagerForSession({agentId, sessionId})facade แบบ static เก่าSessionManager.create/openForSession/list/forkFromSessionถูกลบแล้ว เพื่อให้ การทดสอบและโค้ดรันไทม์ไม่สามารถสร้างการค้นพบเซสชันยุคไฟล์ขึ้นใหม่โดยไม่ตั้งใจ - รันไทม์ Plugin จะไม่ expose
api.runtime.agent.session.resolveTranscriptLocatorPathอีกต่อไป; โค้ด Plugin ใช้ helper แถว SQLite และค่าขอบเขต - พื้นผิว SDK สาธารณะ
session-store-runtimeตอนนี้ export เฉพาะ helper แถวเซสชัน และแถว transcript เท่านั้น Helper schema/path/transaction ของ SQLite ที่เฉพาะเจาะจง อยู่ในsqlite-runtime; helper open/close/reset ดิบยังเป็น local-only สำหรับ การทดสอบ first-party - ตัว classifier ชื่อไฟล์ trajectory/checkpoint
.jsonllegacy ตอนนี้อยู่ใน module session-file legacy ของ doctor การ validate เซสชันหลักจะไม่นำเข้า helper file-artifact เพื่อใช้ตัดสิน session id SQLite ปกติอีกต่อไป - รัน subagent แบบ blocking ของ Active Memory ใช้แถว transcript SQLite แทน
การสร้างไฟล์
session.jsonlชั่วคราวหรือ persisted ใต้สถานะ Plugin ตัวเลือกtranscriptDirแบบเก่าถูกลบแล้ว - การสร้าง slug แบบครั้งเดียวและรัน planner ของ Crestodian ใช้แถว transcript SQLite
แทนการสร้างไฟล์
session.jsonlชั่วคราว - รัน helper
llm-taskและการสกัด commitment ที่ซ่อนอยู่ก็ใช้แถว transcript SQLite เช่นกัน ดังนั้นเซสชัน helper เฉพาะโมเดลเหล่านี้จะไม่สร้างไฟล์ transcript JSON/JSONL ชั่วคราวอีกต่อไป TranscriptSessionManagerตอนนี้เป็นเพียงขอบเขต transcript SQLite ที่เปิดแล้ว โค้ดรันไทม์เปิดด้วยopenTranscriptSessionManagerForSession({agentId, sessionId}); flow create, branch, continue, list และ fork อยู่ใน helper แถว SQLite ที่เป็นเจ้าของ แทน facade manager แบบ static โค้ด Doctor/import/debug จัดการไฟล์ต้นทาง legacy ที่ชัดเจนภายนอก runtime session manager- method facade
SessionManager.newSession()และSessionManager.createBranchedSession()ที่ stale ถูกลบแล้ว เซสชันใหม่ และ descendant ของ transcript ถูกสร้างโดย workflow SQLite ที่เป็นเจ้าของ แทนการ mutate manager ที่เปิดอยู่แล้วให้กลายเป็นเซสชัน persisted อื่น - การตัดสินใจ fork parent transcript และการสร้าง fork จะไม่รับ
storePathหรือsessionsDirอีกต่อไป โดยใช้ขอบเขต transcript SQLite{agentId, sessionId}แทน metadata path filesystem ที่เก็บไว้ - memory-host จะไม่ export helper classification ของ transcript ใน session-directory แบบ no-op อีกต่อไป; การกรอง transcript ตอนนี้อนุมานจาก metadata แถว SQLite ระหว่างการสร้าง entry
- การทดสอบ session-export ของ memory-host และ QMD ใช้ขอบเขต transcript SQLite
path เก่า
agents/<agentId>/sessions/*.jsonlยังครอบคลุมเฉพาะในที่ที่การทดสอบ ตั้งใจพิสูจน์ความเข้ากันได้ของ doctor/import/export - การตรวจสอบเซสชัน raw ของ QA-lab ตอนนี้ใช้
sessions.listผ่าน Gateway แทนการอ่านagents/qa/sessions/sessions.json; ฟีดแบ็ก MSteams ผนวกเข้ากับทรานสคริปต์ SQLite โดยตรงโดยไม่สร้าง path JSONL ปลอม - รอบของช่องทางขาเข้าที่ใช้ร่วมกันตอนนี้พก
{agentId, sessionKey}แทนstorePathแบบเดิม path การบันทึกของ LINE, WhatsApp, Slack, Discord, Telegram, Matrix, Signal, iMessage, BlueBubbles, Feishu, Google Chat, IRC, Nextcloud Talk, Zalo, Zalo Personal, QA Channel, Microsoft Teams, Mattermost, Synology Chat, Tlon, Twitch, และ QQBot ตอนนี้อ่านเมทาดาต้า updated-at และบันทึกแถวเซสชันขาเข้า ผ่านตัวตน SQLite - เอาการคงอยู่ของตัวระบุตำแหน่งทรานสคริปต์ออกจากแถวเซสชันที่ใช้งานอยู่แล้ว
resolveSessionTranscriptTargetส่งคืนagentId,sessionId, และเมทาดาต้า หัวข้อที่เป็นทางเลือก; doctor เป็นโค้ดเดียวที่นำเข้าชื่อไฟล์ทรานสคริปต์เดิม - ส่วนหัวทรานสคริปต์รันไทม์เริ่มที่ SQLite เวอร์ชัน
1การอัปเกรดรูปแบบ JSONL V1/V2/V3 เก่าอยู่เฉพาะในการนำเข้า doctor และปรับส่วนหัวที่นำเข้าให้เป็น เวอร์ชันทรานสคริปต์ SQLite ปัจจุบันก่อนจัดเก็บแถว - การ์ด database-first ตอนนี้ห้าม
SessionManager.listAllและSessionManager.forkFromSession; เวิร์กโฟลว์การแสดงรายการเซสชันและ fork/restore ต้องอยู่บน API SQLite แบบแถว/มีขอบเขต - การ์ดยังห้ามชื่อ helper แบบเดิมสำหรับ parse ทรานสคริปต์ JSONL/ซ่อม active-branch นอกโค้ด doctor/import เพื่อไม่ให้รันไทม์ขยาย path การย้ายทรานสคริปต์เดิมตัวที่สอง
- การรัน PI แบบฝังปฏิเสธ handle ทรานสคริปต์ขาเข้า โดยใช้ตัวตน SQLite
{agentId, sessionId}ก่อนเปิด worker และอีกครั้งก่อน attempt แตะสถานะทรานสคริปต์ อินพุต/tmp/*.jsonlที่ค้างเก่าไม่สามารถเลือก เป้าหมายการเขียนรันไทม์ได้ - ระเบียน cache trace, payload Anthropic, raw stream, และไทม์ไลน์ diagnostics
ตอนนี้เขียนไปยังแถว SQLite
diagnostic_eventsแบบมีชนิด บันเดิลความเสถียรของ Gateway ตอนนี้เขียนไปยังแถว SQLitediagnostic_stability_bundlesแบบมีชนิด path override JSONL เก่าdiagnostics.cacheTrace.filePath,OPENCLAW_CACHE_TRACE_FILE,OPENCLAW_ANTHROPIC_PAYLOAD_LOG_FILE, และOPENCLAW_DIAGNOSTICS_TIMELINE_PATHถูกเอาออกแล้ว และการจับภาพความเสถียรปกติ จะไม่เขียนไฟล์logs/stability/*.jsonอีกต่อไป - การคงอยู่ของ Cron ตอนนี้ reconcile แถว SQLite
cron_jobsแทนการ ลบ/แทรกซ้ำทั้งตารางงานในแต่ละครั้งที่บันทึก การ writeback เป้าหมาย Plugin อัปเดตแถว cron ที่ตรงกันโดยตรงและคงสถานะ cron รันไทม์ไว้ใน ทรานแซกชัน state-database เดียวกัน - caller รันไทม์ Cron ตอนนี้ใช้คีย์ store cron SQLite ที่เสถียร path
cron.storeเดิมเป็นอินพุตนำเข้าของ doctor เท่านั้น; path writeback เป้าหมายของ Gateway ฝั่ง production, การบำรุงรักษางาน, สถานะ, run-log, และ Telegram ใช้resolveCronStoreKeyและไม่ทำ path-normalize คีย์อีกต่อไป ตอนนี้สถานะ Cron รายงานstoreKeyแทนฟิลด์storePathรูปไฟล์แบบเก่า - การโหลดและการจัดกำหนดการรันไทม์ Cron ไม่ normalize รูปแบบงานที่คงอยู่แบบเดิมอีกต่อไป
เช่น
jobId,schedule.cron,atMsแบบตัวเลข, boolean แบบ string, หรือsessionTargetที่หายไป การนำเข้า legacy ของ doctor เป็นเจ้าของการซ่อมเหล่านั้นก่อนแทรกแถว ลงใน SQLite - ACP spawn ไม่ resolve หรือคงอยู่ path ไฟล์ JSONL ของทรานสคริปต์อีกต่อไป การตั้งค่า spawn และ thread-bind คงอยู่แถวเซสชัน SQLite โดยตรงและเก็บ session id เป็นตัวตนทรานสคริปต์ที่ retained
- API เมทาดาต้าเซสชัน ACP ตอนนี้อ่าน/list/upsert แถว SQLite ตาม
agentIdและ ไม่เปิดเผยstorePathเป็นส่วนหนึ่งของสัญญา entry เซสชัน ACP อีกต่อไป - การบัญชีการใช้งานเซสชันและการรวมการใช้งานของ Gateway ตอนนี้ resolve ทรานสคริปต์
ด้วย
{agentId, sessionId}เท่านั้น cache cost/usage และสรุป discovered-session ไม่สังเคราะห์หรือส่งคืน string ตัวระบุตำแหน่งทรานสคริปต์อีกต่อไป - Gateway chat append, การคงอยู่ abort-partial,
/sessions.send, และ การเขียนทรานสคริปต์สื่อ webchat ผนวกโดยตรงผ่าน scope ทรานสคริปต์ SQLite helper transcript-injection ของ Gateway ไม่รับพารามิเตอร์transcriptLocatorอีกต่อไป - การค้นพบททรานสคริปต์ SQLite ตอนนี้แสดงเฉพาะ scope และ stats ของทรานสคริปต์:
{agentId, sessionId, updatedAt, eventCount}helper compatibilitylistSqliteSessionTranscriptLocatorsที่เลิกใช้แล้วและฟิลด์locatorต่อแถวหายไปแล้ว - รันไทม์ซ่อมทรานสคริปต์ตอนนี้เปิดเผยเฉพาะ
repairTranscriptSessionStateIfNeeded({agentId, sessionId})helper ซ่อมแบบใช้ locator เก่าถูกลบแล้ว; โค้ด doctor/debug อ่าน path ไฟล์ต้นทางที่ชัดเจน และไม่ย้าย string locator - รันไทม์ ledger การ replay ของ ACP ตอนนี้เก็บแถว replay ต่อเซสชันในฐานข้อมูลสถานะ
SQLite ที่ใช้ร่วมกันแทน
acp/event-ledger.json; doctor นำเข้าและ เอาไฟล์เดิมออก - helper ตัวอ่านทรานสคริปต์ของ Gateway ตอนนี้อยู่ใน
src/gateway/session-transcript-readers.tsแทนชื่อโมดูลsession-utils.fsเก่า การตรวจสอบ fallback retry history ตั้งชื่อตาม เนื้อหาทรานสคริปต์ SQLite แทนพื้นผิว file-helper เก่า - helper injected-chat และ compaction ของ Gateway ตอนนี้ส่ง scope ทรานสคริปต์ SQLite ผ่าน API helper ภายในแทนการตั้งค่าชื่อเป็น path ทรานสคริปต์หรือ ไฟล์ต้นทาง
- การตรวจจับ bootstrap continuation ตอนนี้ตรวจแถวทรานสคริปต์ SQLite ผ่าน
hasCompletedBootstrapTranscriptTurn; ไม่เปิดเผยชื่อ helper รูปไฟล์อีกต่อไป - การทดสอบ embedded-runner ตอนนี้ใช้ตัวตนทรานสคริปต์ SQLite และการเปิด
transcript manager ใหม่ต้องมี
sessionIdที่ชัดเจนเสมอ - helper การทำดัชนีหน่วยความจำตอนนี้ใช้คำศัพท์ทรานสคริปต์ SQLite ตลอดทั้งระบบ:
host export
listSessionTranscriptScopesForAgentและsessionTranscriptKeyForScope, คิว targeted sync คือsessionTranscripts, hit การค้นหาเซสชันสาธารณะเปิดเผย path ทึบtranscript:<agent>:<session>, และคีย์แหล่ง DB ภายในคือsession:<session>ภายใต้source_kind='sessions'แทน path ไฟล์ปลอม - helper persistent-dedupe ของ plugin SDK ทั่วไปไม่เปิดเผยตัวเลือกที่มีรูปไฟล์อีกต่อไป caller ให้คีย์ scope SQLite และแถว dedupe ถาวรอยู่ใน สถานะ Plugin ที่ใช้ร่วมกัน
- โทเค็น SSO ของ Microsoft Teams ย้ายจากไฟล์ JSON ที่ล็อกไว้ไปยังสถานะ Plugin
SQLite แล้ว Doctor นำเข้า
msteams-sso-tokens.json, สร้างคีย์โทเค็น SSO แบบ canonical ใหม่จาก payload และเอาไฟล์ต้นทางออก โทเค็น OAuth แบบ delegated ยังคงอยู่บนขอบเขตไฟล์ credential ส่วนตัวเดิม - สถานะ cache การ sync ของ Matrix ย้ายจาก
bot-storage.jsonไปยังสถานะ Plugin SQLite แล้ว Doctor นำเข้า payload sync แบบ raw หรือ wrapped เดิมและเอา ไฟล์ต้นทางออก ไคลเอนต์ Matrix และ QA Matrix ที่ใช้งานอยู่ส่ง directory ราก sync-store ของ SQLite ไม่ใช่ pathsync-store.jsonหรือbot-storage.jsonปลอม - สถานะการย้าย crypto เดิมของ Matrix ย้ายจาก
legacy-crypto-migration.jsonไปยังสถานะ Plugin SQLite แล้ว Doctor นำเข้า ไฟล์สถานะเก่า; snapshot IndexedDB ของ Matrix SDK ย้ายจากcrypto-idb-snapshot.jsonไปยัง blob ของ Plugin SQLite แล้ว recovery key และ credential ของ Matrix เป็นแถว plugin-state ของ SQLite; ไฟล์ JSON เก่าของรายการเหล่านี้เป็นเพียง อินพุตการย้ายของ doctor เท่านั้น - log กิจกรรม Memory Wiki ตอนนี้ใช้สถานะ Plugin SQLite แทน
.openclaw-wiki/log.jsonlprovider การย้าย Memory Wiki นำเข้า log JSONL เก่า; markdown ของ wiki และเนื้อหา vault ของผู้ใช้ยังคงมีไฟล์เป็น backend ในฐานะ เนื้อหา workspace - Memory Wiki ไม่สร้าง
.openclaw-wiki/state.jsonหรือ directory.openclaw-wiki/locksที่ไม่ได้ใช้อีกต่อไป provider การย้ายเอาไฟล์เมทาดาต้า Plugin ที่เลิกใช้แล้วเหล่านั้นออกหาก vault เก่ายังมีอยู่ - entry audit ของ Crestodian ตอนนี้ใช้สถานะ Plugin SQLite ของ core แทน
audit/crestodian.jsonlDoctor นำเข้า log audit JSONL เดิมและ เอาออกหลังนำเข้าสำเร็จ - entry audit การเขียน/สังเกต config ตอนนี้ใช้สถานะ Plugin SQLite ของ core
แทน
logs/config-audit.jsonlDoctor นำเข้า log audit JSONL เดิมและ เอาออกหลังนำเข้าสำเร็จ - companion ของ macOS ไม่เขียน sidecar
logs/config-audit.jsonlหรือlogs/config-health.jsonแบบ app-local ขณะแก้ไขopenclaw.jsonอีกต่อไป ไฟล์ config ยังคงมีไฟล์เป็น backend, snapshot การกู้คืนอยู่ถัดจากไฟล์ config, และสถานะ audit/health ของ config แบบถาวรเป็นของ store SQLite ของ Gateway - pending approval ของ Crestodian rescue ตอนนี้ใช้สถานะ Plugin SQLite ของ core
แทน
crestodian/rescue-pending/*.jsonDoctor นำเข้าไฟล์ pending approval เดิมและเอาออกหลังนำเข้าสำเร็จ - สถานะ arm ชั่วคราวของ Phone Control ตอนนี้ใช้สถานะ Plugin SQLite แทน
plugins/phone-control/armed.jsonDoctor นำเข้าไฟล์ armed-state เดิม ไปยัง namespacephone-control/arm-stateและเอาไฟล์ออก - Doctor ไม่ซ่อมทรานสคริปต์ JSONL แบบ in place หรือสร้างไฟล์ JSONL สำรอง อีกต่อไป โดยนำเข้า active branch ไปยัง SQLite และเอา source เดิมออก
- การค้นหาทรานสคริปต์ของ hook session-memory ใช้การอ่าน SQLite แบบ scope-only
{agentId, sessionId}helper ของมันไม่รับหรือ derive ตัวระบุตำแหน่งทรานสคริปต์, การอ่านไฟล์เดิม, หรือตัวเลือก rewrite ไฟล์อีกต่อไป - binding การสนทนา app-server ของ Codex ตอนนี้ key สถานะ Plugin SQLite ตาม
คีย์เซสชัน OpenClaw หรือ scope
{agentId, sessionId}ที่ชัดเจน ต้องไม่ เก็บ binding fallback แบบ transcript-path ไว้ - การอ่าน mirrored-history ของ app-server Codex ใช้เฉพาะ scope ทรานสคริปต์ SQLite; ต้องไม่กู้คืนตัวตนจาก path ไฟล์ทรานสคริปต์
- path role-ordering และ compaction reset ไม่ unlink ไฟล์ทรานสคริปต์เก่าอีกต่อไป; reset หมุนเฉพาะแถวเซสชัน SQLite และตัวตนทรานสคริปต์
- response ของ Gateway reset และ checkpoint ส่งคืนแถวเซสชันสะอาดพร้อม session id ไม่สังเคราะห์ตัวระบุตำแหน่งทรานสคริปต์ SQLite ให้ไคลเอนต์อีกต่อไป
- Dreaming ของ memory-core ไม่ prune แถวเซสชันด้วยการ probe หาไฟล์ JSONL
ที่หายไปอีกต่อไป การ cleanup subagent ผ่าน API รันไทม์เซสชันแทน
การตรวจสอบการมีอยู่ของ filesystem การทดสอบ transcript-ingestion seed แถว SQLite
โดยตรงแทนการสร้าง fixture
agents/<id>/sessionsหรือ placeholder locator - การทำดัชนีทรานสคริปต์หน่วยความจำอาจเปิดเผย
transcript:<agentId>:<sessionId>เป็น path hit การค้นหาเสมือนสำหรับ helper citation/read แหล่งดัชนีถาวรเป็นแบบ relational (source_kind='sessions',source_key='session:<sessionId>',session_id=<sessionId>) ดังนั้นค่านี้ไม่ใช่ locator ทรานสคริปต์รันไทม์, ไม่ใช่ path filesystem, และต้องไม่ถูกส่งกลับเข้า API รันไทม์เซสชันโดยเด็ดขาด - สถานะหน่วยความจำของ Gateway doctor อ่านจำนวน short-term recall และ phase-signal
จากแถว plugin-state ของ SQLite แทน
memory/.dreams/*.json; เอาต์พุต CLI และ doctor ตอนนี้ติดป้าย storage นั้นเป็น store SQLite ไม่ใช่ path - รันไทม์ memory-core, สถานะ CLI, เมธอด Gateway doctor, และ facade ของ plugin SDK
ไม่ audit หรือ archive ไฟล์
.dreams/session-corpusเดิมอีกต่อไป ไฟล์เหล่านั้นเป็นอินพุตการย้ายเท่านั้น; doctor นำเข้าไปยัง SQLite และ ลบ source หลังการตรวจสอบ แถวหลักฐาน active session-ingestion ตอนนี้ใช้ path SQLite เสมือนmemory/session-ingestion/<day>.txt; รันไทม์ ไม่เขียนหรือ derive สถานะจาก.dreams/session-corpus - artifact สาธารณะของ memory-core เปิดเผย event ของ host SQLite เป็น artifact JSON
เสมือน
memory/events/memory-host-events.json; ไม่ใช้ path source.dreams/events.jsonlเดิมซ้ำอีกต่อไป - registry ของ sandbox container/browser ตอนนี้ใช้ตาราง SQLite
sandbox_registry_entriesที่ใช้ร่วมกัน พร้อมคอลัมน์ session, image, timestamp, backend/config, และ browser port แบบมีชนิด Doctor นำเข้าไฟล์ registry JSON แบบ monolithic และ sharded เดิมและเอา source ที่สำเร็จออก การอ่านรันไทม์ใช้คอลัมน์แถวแบบมีชนิด เป็นแหล่งความจริง;entry_jsonเป็นเพียงสำเนาสำหรับ replay/debug - Commitments ตอนนี้ใช้ตาราง
commitmentsที่ใช้ร่วมกันแบบมีชนิดแทน blob JSON ทั้ง store การบันทึก snapshot upsert ตาม commitment id และลบเฉพาะ แถวที่หายไปแทนการ clear และแทรกตารางใหม่ รันไทม์โหลด commitments จากคอลัมน์ scope, delivery-window, status, attempt, และ text แบบมีชนิด;record_jsonเป็นเพียงสำเนาสำหรับ replay/debug Doctor นำเข้าcommitments.jsonเดิมและเอาออกหลังนำเข้าสำเร็จ - นิยามงาน Cron, สถานะ schedule, และประวัติการรันไม่มี writer หรือ reader JSON
ในรันไทม์อีกต่อไป รันไทม์ใช้แถว
cron_jobsพร้อม schedule แบบมีชนิด, คอลัมน์ payload, delivery, failure-alert, session, status และ runtime-state รวมถึงเมตาดาต้าcron_run_logsที่มีชนิดกำกับสำหรับสถานะ, สรุปการวินิจฉัย, สถานะ/ข้อผิดพลาดการส่งมอบ, เซสชัน/การรัน, โมเดล และยอดรวมโทเค็นjob_jsonเป็นเพียงสำเนาสำหรับเล่นซ้ำ/ดีบัก;state_jsonเก็บการวินิจฉัยรันไทม์แบบซ้อนที่ยังไม่มีฟิลด์สำหรับคิวรีร้อน ขณะที่รันไทม์ เติมฟิลด์สถานะร้อนกลับจากคอลัมน์ที่มีชนิดกำกับ doctor นำเข้า ไฟล์jobs.json,jobs-state.jsonและruns/*.jsonlเดิม แล้วลบ แหล่งข้อมูลที่นำเข้า การเขียนกลับเป้าหมาย Plugin จะอัปเดตแถวcron_jobsที่ตรงกันแทนการโหลดและแทนที่ cron store ทั้งหมด - การเริ่มต้น Gateway จะละเว้นเครื่องหมาย
notify: trueเดิมในการฉายภาพรันไทม์ doctor จะแปลงเครื่องหมายเหล่านั้นเป็นการส่งมอบ SQLite แบบชัดเจนเมื่อcron.webhookถูกต้อง ลบเครื่องหมายที่ไม่มีผลเมื่อไม่ได้ตั้งค่า และเก็บ เครื่องหมายไว้พร้อมคำเตือนเมื่อ Webhook ที่กำหนดค่าไว้ไม่ถูกต้อง - คิวการส่งออกและการส่งมอบเซสชันตอนนี้เก็บสถานะคิว, ชนิดรายการ,
คีย์เซสชัน, ช่องทาง, เป้าหมาย, ID บัญชี, จำนวนการลองซ้ำ, ความพยายาม/ข้อผิดพลาดล่าสุด,
สถานะการกู้คืน และเครื่องหมายการส่งของแพลตฟอร์มเป็นคอลัมน์ที่มีชนิดกำกับในตาราง
delivery_queue_entriesที่ใช้ร่วมกัน การกู้คืนรันไทม์อ่านฟิลด์ร้อนเหล่านั้นจาก คอลัมน์ที่มีชนิดกำกับ และการเปลี่ยนแปลงการลองซ้ำ/การกู้คืนจะอัปเดตคอลัมน์เหล่านั้นโดยตรง โดยไม่เขียน JSON สำหรับเล่นซ้ำใหม่ เพย์โหลด JSON เต็มยังคงอยู่เฉพาะในฐานะ บล็อบสำหรับเล่นซ้ำ/ดีบักสำหรับเนื้อหาข้อความและข้อมูลเล่นซ้ำเย็นอื่นๆ - ระเบียนรูปภาพขาออกที่จัดการตอนนี้ใช้แถว
managed_outgoing_image_recordsที่ใช้ร่วมกันและมีชนิดกำกับ โดยไบต์สื่อยังคงเก็บในmedia_blobsระเบียน JSON ยังคงเป็นเพียงสำเนาสำหรับเล่นซ้ำ/ดีบัก - ค่ากำหนดตัวเลือกโมเดลของ Discord, แฮชการ deploy คำสั่ง และการผูกเธรด ตอนนี้ใช้สถานะ Plugin ใน SQLite ที่ใช้ร่วมกัน แผนนำเข้า JSON เดิมของส่วนเหล่านี้อยู่ในพื้นผิว setup/doctor migration ของ Plugin Discord ไม่ใช่ในโค้ด migration หลัก
- ตัวตรวจจับการนำเข้าดั้งเดิมของ Plugin ใช้โมดูลที่ตั้งชื่อตาม doctor เช่น
doctor-legacy-state.tsหรือdoctor-state-imports.ts; โมดูลรันไทม์ช่องทางปกติ ต้องไม่นำเข้าตัวตรวจจับ JSON เดิม - เคอร์เซอร์ catchup ของ BlueBubbles และเครื่องหมาย dedupe ขาเข้าตอนนี้ใช้สถานะ Plugin ใน SQLite ที่ใช้ร่วมกัน แผนนำเข้า JSON เดิมของส่วนเหล่านี้อยู่ในพื้นผิว setup/doctor migration ของ Plugin BlueBubbles ไม่ใช่ในโค้ด migration หลัก
- ออฟเซ็ตอัปเดตของ Telegram, แถวแคชสติกเกอร์, แถวแคชข้อความที่ส่งแล้ว, แถวแคชชื่อหัวข้อ และการผูกเธรดตอนนี้ใช้สถานะ Plugin ใน SQLite ที่ใช้ร่วมกัน แผนนำเข้า JSON เดิมของส่วนเหล่านี้อยู่ในพื้นผิว setup/doctor migration ของ Plugin Telegram ไม่ใช่ในโค้ด migration หลัก
- เคอร์เซอร์ catchup ของ iMessage, การแมป short-id ของการตอบกลับ และแถว dedupe ของ sent-echo
ตอนนี้ใช้สถานะ Plugin ใน SQLite ที่ใช้ร่วมกัน ไฟล์
imessage/catchup/*.json,imessage/reply-cache.jsonlและimessage/sent-echoes.jsonlเดิมเป็น อินพุตของ doctor เท่านั้น - แถว dedupe ข้อความของ Feishu ตอนนี้ใช้สถานะ Plugin ใน SQLite ที่ใช้ร่วมกันแทน
ไฟล์
feishu/dedup/*.jsonแผนนำเข้า JSON เดิมของส่วนนี้อยู่ในพื้นผิว setup/doctor migration ของ Plugin Feishu ไม่ใช่ในโค้ด migration หลัก - การสนทนา, โพล, บัฟเฟอร์อัปโหลดที่ค้างอยู่ และการเรียนรู้จากฟีดแบ็กของ Microsoft Teams
ตอนนี้ใช้ตารางสถานะ/บล็อบของ Plugin ใน SQLite ที่ใช้ร่วมกัน เส้นทางอัปโหลดที่ค้างอยู่
ใช้
plugin_blob_entriesเพื่อให้บัฟเฟอร์สื่อถูกเก็บเป็น SQLite BLOB แทน JSON แบบ base64 ชื่อตัวช่วยรันไทม์ตอนนี้ใช้การตั้งชื่อแบบ SQLite/state แทนการตั้งชื่อ file-store แบบ*-fsและ shimstorePathเดิมถูกลบ ออกจาก store เหล่านี้แล้ว แผนนำเข้า JSON เดิมของส่วนนี้อยู่ในพื้นผิว setup/doctor migration ของ Plugin Microsoft Teams - สื่อขาออกที่โฮสต์โดย Zalo ตอนนี้ใช้
plugin_blob_entriesของ SQLite ที่ใช้ร่วมกัน แทนไฟล์ข้างเคียงชั่วคราว JSON/bin ของopenclaw-zalo-outbound-media - HTML และเมตาดาต้าของตัวดู Diffs ตอนนี้ใช้
plugin_blob_entriesของ SQLite ที่ใช้ร่วมกัน แทนไฟล์ชั่วคราวmeta.json/viewer.htmlเอาต์พุต PNG/PDF ที่เรนเดอร์แล้วคงเป็น การ materialize ชั่วคราว เพราะการส่งมอบของช่องทางยังต้องใช้พาธไฟล์ - เอกสารที่จัดการโดย Canvas ตอนนี้ใช้
plugin_blob_entriesของ SQLite ที่ใช้ร่วมกัน แทนไดเรกทอรีเริ่มต้นstate/canvas/documentsโฮสต์ Canvas ให้บริการบล็อบเหล่านั้น โดยตรง; ไฟล์โลคัลถูกสร้างเฉพาะสำหรับเนื้อหา operator แบบhost.rootที่ระบุชัดเจน หรือการ materialize ชั่วคราวเมื่อ media reader ปลายน้ำ ต้องใช้พาธ - การตัดสินใจ audit ของ File Transfer ตอนนี้ใช้
plugin_state_entriesของ SQLite ที่ใช้ร่วมกัน แทนบันทึกรันไทม์audit/file-transfer.jsonlที่ไม่จำกัดขนาด doctor นำเข้าไฟล์ audit JSONL เดิมเข้าสู่สถานะ Plugin และลบแหล่งข้อมูล หลังนำเข้าสะอาดแล้ว - lease กระบวนการ ACPX และตัวตนอินสแตนซ์ Gateway ตอนนี้ใช้สถานะ Plugin
ใน SQLite ที่ใช้ร่วมกัน doctor นำเข้าไฟล์
gateway-instance-idเดิมเข้าสู่สถานะ Plugin และลบแหล่งข้อมูล - สคริปต์ wrapper ที่ ACPX สร้างขึ้นและ Codex home ที่แยกไว้เป็นการ materialize ชั่วคราว
ภายใต้ temp root ของ OpenClaw ไม่ใช่สถานะ OpenClaw แบบถาวร ระเบียนรันไทม์ ACPX
แบบถาวรคือแถว lease ของ SQLite และแถว gateway-instance;
พื้นผิว config
stateDirของ ACPX เดิมถูกลบแล้ว เพราะไม่มีสถานะรันไทม์ ถูกเขียนไว้ที่นั่นอีกต่อไป - ไฟล์แนบสื่อของ Gateway ตอนนี้ใช้ตาราง SQLite
media_blobsที่ใช้ร่วมกันเป็น byte store ตามหลัก พาธโลคัลที่ส่งคืนให้พื้นผิวความเข้ากันได้ของช่องทางและ sandbox เป็นการ materialize ชั่วคราวของแถวฐานข้อมูล ไม่ใช่ media store แบบถาวร allowlist สื่อรันไทม์ไม่รวม root เดิม$OPENCLAW_STATE_DIR/mediaหรือmediaใน config-dir อีกต่อไป; ไดเรกทอรีเหล่านั้นเป็น แหล่งนำเข้าของ doctor เท่านั้น - Shell completion ไม่เขียนไฟล์แคช
$OPENCLAW_STATE_DIR/completions/*อีกต่อไป เส้นทาง smoke ของ install, doctor, update และ release ใช้เอาต์พุต completion ที่สร้างขึ้นหรือการ source โปรไฟล์แทนไฟล์แคช completion แบบถาวร - การ staging การอัปโหลด Skills ของ Gateway ตอนนี้ใช้แถว
skill_uploadsที่ใช้ร่วมกัน เมตาดาต้าอัปโหลด, idempotency key และไบต์ archive อยู่ใน SQLite; installer ได้รับเฉพาะพาธ archive ที่ materialize ชั่วคราวระหว่างที่การติดตั้ง กำลังทำงาน - ไฟล์แนบ inline ของ subagent ไม่ materialize ภายใต้ workspace
.openclaw/attachments/*อีกต่อไป เส้นทาง spawn เตรียมรายการ seed ของ SQLite VFS, การรัน inline seed รายการเหล่านั้นเข้าสู่ namespace scratch ของรันไทม์ต่อเอเจนต์, และเครื่องมือที่อิงดิสก์ overlay scratch ของ SQLite นั้นสำหรับพาธไฟล์แนบ คอลัมน์ registry attachment-dir ของ subagent-run เดิมและ cleanup hook ถูกลบแล้ว - การ hydrate รูปภาพของ CLI ไม่ดูแลไฟล์แคช
openclaw-cli-imagesที่เสถียรอีกต่อไป แบ็กเอนด์ CLI ภายนอกยังคงได้รับพาธไฟล์ แต่พาธเหล่านั้นเป็นการ materialize ชั่วคราวรายรันพร้อม cleanup - การวินิจฉัย cache-trace, การวินิจฉัยเพย์โหลด Anthropic, การวินิจฉัย raw model stream,
อีเวนต์ไทม์ไลน์การวินิจฉัย และบันเดิลเสถียรภาพของ Gateway ตอนนี้
เขียนแถว SQLite แทนไฟล์
logs/*.jsonlหรือlogs/stability/*.jsonแฟล็กและ env var สำหรับ override พาธรันไทม์ถูกลบแล้ว; คำสั่ง export/debug สามารถ materialize ไฟล์จากแถวฐานข้อมูลได้โดยชัดเจน - companion บน macOS ไม่มี writer
diagnostics.jsonlแบบ rolling อีกต่อไป บันทึกของแอป ไปยัง unified logging และการวินิจฉัย Gateway แบบถาวรยังคงหนุนด้วย SQLite - รายการระเบียน port-guardian ของ macOS ตอนนี้ใช้แถว
macos_port_guardian_recordsของ SQLite ที่ใช้ร่วมกันและมีชนิดกำกับ แทนไฟล์ JSON ใน Application Support หรือบล็อบ singleton แบบทึบ - singleton lock ของ Gateway ตอนนี้ใช้แถว
state_leasesของ SQLite ที่ใช้ร่วมกันและมีชนิดกำกับภายใต้ scopegateway_locksแทนไฟล์ lock ใน temp-dir เอกสารแก้ปัญหา Fly และ OAuth ตอนนี้ชี้ไปที่ lease ของ SQLite/auth refresh lock แทน cleanup file-lock ที่ล้าสมัย - สถานะ restart sentinel ของ Gateway ตอนนี้ใช้แถว
gateway_restart_sentinelของ SQLite ที่ใช้ร่วมกันและมีชนิดกำกับ แทนrestart-sentinel.json; รันไทม์ อ่านชนิด sentinel, สถานะ, routing, ข้อความ, continuation และสถิติจาก คอลัมน์ที่มีชนิดกำกับpayload_jsonเป็นเพียงสำเนาสำหรับเล่นซ้ำ/ดีบัก โค้ดรันไทม์ล้าง แถว SQLite โดยตรงและไม่พก plumbing cleanup ไฟล์อีกต่อไป - สถานะ restart intent และ supervisor handoff ของ Gateway ตอนนี้ใช้แถว
gateway_restart_intentและgateway_restart_handoffของ SQLite ที่ใช้ร่วมกันและมีชนิดกำกับ แทนไฟล์ข้างเคียงgateway-restart-intent.jsonและgateway-supervisor-restart-handoff.json - การประสาน singleton ของ Gateway ตอนนี้ใช้แถว
state_leasesที่มีชนิดกำกับภายใต้gateway_locksแทนการเขียนไฟล์gateway.<hash>.lockแถว lease ถือครอง owner ของ lock, expiry, heartbeat และเพย์โหลดดีบัก; SQLite ถือครอง ขอบเขต acquire/release แบบ atomic ตัวเลือกไดเรกทอรี file-lock ที่เลิกใช้แล้วถูกลบ; การทดสอบใช้ตัวตนแถว SQLite โดยตรง - ตัวช่วยรายงานการใช้งาน cron เก่าที่ไม่มีการอ้างอิงซึ่งสแกนไฟล์
cron/runs/*.jsonlถูกลบแล้ว รายงานประวัติการรัน Cron ควรอ่านแถว SQLitecron_run_logsที่มีชนิดกำกับ - การกู้คืนการ restart ของ main-session ตอนนี้ค้นหาเอเจนต์ตัวเลือกผ่าน registry
agent_databasesของ SQLite แทนการสแกนไดเรกทอรีagents/*/sessions - การกู้คืน session-corruption ของ Gemini ตอนนี้ลบเฉพาะแถวเซสชันใน SQLite;
ไม่ต้องใช้ gate
storePathเดิมหรือพยายาม unlink พาธ transcript JSONL ที่ derive มาอีกต่อไป - การจัดการ path override ตอนนี้ถือค่า environment แบบ literal
undefined/nullว่าไม่ได้ตั้งค่า ป้องกันฐานข้อมูลundefined/state/*.sqliteใต้ repo-root โดยไม่ตั้งใจระหว่างการทดสอบหรือการ handoff ผ่าน shell - ลายนิ้วมือสุขภาพ config ตอนนี้ใช้แถว
config_health_entriesของ SQLite ที่ใช้ร่วมกันและมีชนิดกำกับ แทนlogs/config-health.jsonทำให้ไฟล์ config ปกติเป็น เอกสารการกำหนดค่าเดียวที่ไม่ใช่ credential companion บน macOS เก็บเฉพาะ สถานะสุขภาพแบบ process-local และไม่สร้างไฟล์ข้างเคียง JSON เก่าขึ้นใหม่ - รันไทม์ auth profile ไม่ได้นำเข้าหรือเขียนไฟล์ JSON credential อีกต่อไป
credential store ตามหลักคือ SQLite;
auth-profiles.json,auth.jsonต่อเอเจนต์ และcredentials/oauth.jsonที่ใช้ร่วมกันเป็นอินพุต doctor migration ที่ถูกลบหลังนำเข้า - การทดสอบ save/state ของ auth profile ตอนนี้ assert ตาราง auth ของ SQLite ที่มีชนิดกำกับโดยตรง และใช้ชื่อไฟล์ auth-profile เดิมเฉพาะสำหรับอินพุต doctor migration
openclaw secrets applyscrub เฉพาะไฟล์ config, env file และ auth-profile store ของ SQLite เท่านั้น มันไม่พก logic ความเข้ากันได้ที่แก้ไขauth.jsonต่อเอเจนต์ที่เลิกใช้แล้วอีกต่อไป; doctor เป็นเจ้าของการนำเข้าและลบไฟล์นั้น- แผนและการ apply migration secret ของ Hermes นำเข้าโปรไฟล์ API-key โดยตรง
เข้าสู่ auth-profile store ของ SQLite ไม่เขียนหรือตรวจสอบ
auth-profiles.jsonเป็นเป้าหมายขั้นกลางอีกต่อไป - เอกสาร auth สำหรับผู้ใช้ตอนนี้อธิบาย
state/openclaw.sqlite#table/auth_profile_stores/<agentDir>แทนการ บอกให้ผู้ใช้ตรวจสอบหรือคัดลอกauth-profiles.json; ชื่อ JSON เดิมของ OAuth/auth ยังคงถูกบันทึกไว้เฉพาะในฐานะอินพุต doctor-import - ตัวช่วยพาธสถานะหลักไม่ expose ไฟล์
credentials/oauth.jsonที่เลิกใช้แล้วอีกต่อไป ชื่อไฟล์เดิมอยู่เฉพาะในเส้นทางนำเข้า auth ของ doctor - เอกสาร install, security, onboarding, model-auth และ SecretRef ตอนนี้อธิบาย แถว auth-profile ของ SQLite และการสำรอง/ย้ายข้อมูลทั้งสถานะ แทน ไฟล์ JSON auth-profile ต่อเอเจนต์
- การค้นพบโมเดล PI ตอนนี้ส่ง credential ตามหลักเข้าสู่ auth storage
pi-coding-agentในหน่วยความจำ มันไม่สร้าง, scrub หรือเขียนauth.jsonต่อเอเจนต์ระหว่างการค้นพบอีกต่อไป - การตั้งค่า trigger และ routing ของ Voice Wake ตอนนี้ใช้ตาราง SQLite ที่ใช้ร่วมกันและมีชนิดกำกับ
แทน
settings/voicewake.json,settings/voicewake-routing.jsonหรือ แถว generic แบบทึบ; doctor นำเข้าไฟล์ JSON เดิมและลบออกหลังจาก migration สำเร็จ - สถานะ update-check ตอนนี้ใช้แถว
update_check_stateที่ใช้ร่วมกันและมีชนิดกำกับ แทนupdate-check.jsonหรือบล็อบ generic แบบทึบ; doctor นำเข้า ไฟล์ JSON เดิมและลบออกหลังจาก migration สำเร็จ - สถานะสุขภาพ config ตอนนี้ใช้แถว
config_health_entriesที่ใช้ร่วมกันและมีชนิดกำกับ แทนlogs/config-health.jsonหรือบล็อบ generic แบบทึบ; doctor นำเข้าไฟล์ JSON เดิมและลบออกหลังจาก migration สำเร็จ - การอนุมัติการผูกการสนทนาของ Plugin ตอนนี้ใช้แถว
plugin_binding_approvalsที่มีชนิดกำกับ แทนสถานะ SQLite ที่ใช้ร่วมกันแบบทึบหรือplugin-binding-approvals.json; ไฟล์ดั้งเดิมเป็นอินพุตสำหรับการย้ายข้อมูลของ doctor - การผูกกับการสนทนาปัจจุบันแบบทั่วไปตอนนี้จัดเก็บแถว
current_conversation_bindingsที่มีชนิดกำกับ แทนการเขียนซ้ำbindings/current-conversations.json; doctor นำเข้าไฟล์ JSON ดั้งเดิมและ ลบไฟล์หลังจากย้ายข้อมูลสำเร็จ - บัญชีแยกประเภทการซิงก์แหล่งที่มาที่นำเข้าของ Memory Wiki ตอนนี้จัดเก็บแถวสถานะ Plugin ของ SQLite
หนึ่งแถวต่อคีย์ vault/source แทนการเขียนซ้ำ
.openclaw-wiki/source-sync.json; ผู้ให้บริการการย้ายข้อมูลนำเข้าและลบบัญชีแยกประเภท JSON ดั้งเดิม - ระเบียน import-run ของ Memory Wiki ChatGPT ตอนนี้จัดเก็บแถวสถานะ Plugin ของ SQLite
หนึ่งแถวต่อ vault/run id แทนการเขียน
.openclaw-wiki/import-runs/*.jsonสแนปช็อต rollback ยังคงเป็นไฟล์ vault แบบชัดเจนจนกว่าการจัดเก็บถาวรของสแนปช็อต import-run จะถูกย้ายไปยังที่เก็บ blob - ไดเจสต์ที่คอมไพล์แล้วของ Memory Wiki ตอนนี้จัดเก็บเป็นแถว blob ของ Plugin ใน SQLite แทนการ
เขียน
.openclaw-wiki/cache/agent-digest.jsonและ.openclaw-wiki/cache/claims.jsonlผู้ให้บริการการย้ายข้อมูลนำเข้าไฟล์แคชเก่า และลบไดเรกทอรีแคชเมื่อว่างเปล่า - การติดตามการติดตั้ง skill ของ ClawHub ตอนนี้จัดเก็บแถวสถานะ Plugin ของ SQLite หนึ่งแถวต่อ
workspace/skill แทนการเขียนหรืออ่าน sidecar
.clawhub/lock.jsonและ.clawhub/origin.jsonตอนรันไทม์ โค้ดรันไทม์ใช้วัตถุสถานะ tracked-install แทน abstraction ของ lockfile/origin ที่มีรูปทรงเหมือนไฟล์ Doctor นำเข้า sidecar ดั้งเดิมจาก workspace ของ agent ที่กำหนดค่าไว้และลบออก หลังจากนำเข้าได้เรียบร้อย - ดัชนี Plugin ที่ติดตั้งแล้วตอนนี้อ่านและเขียนแถว singleton
installed_plugin_indexของ SQLite ร่วมแบบมีชนิดกำกับ แทนplugins/installs.json; ไฟล์ JSON ดั้งเดิมเป็นเพียงอินพุตสำหรับการย้ายข้อมูลของ doctor และจะถูกลบหลังนำเข้า - helper สำหรับพาธ
plugins/installs.jsonดั้งเดิมตอนนี้อยู่ในโค้ด legacy ของ doctor โมดูล plugin-index ของรันไทม์เปิดเผยเฉพาะตัวเลือก persistence ที่มี SQLite หนุนหลัง ไม่ใช่พาธไฟล์ JSON - sentinel การรีสตาร์ทของ Gateway, เจตนาการรีสตาร์ท, และสถานะการส่งต่อให้ supervisor ตอนนี้ใช้
แถว SQLite ร่วมแบบมีชนิดกำกับ (
gateway_restart_sentinel,gateway_restart_intent, และgateway_restart_handoff) แทน blob ทึบแบบทั่วไป โค้ดรีสตาร์ทของรันไทม์ไม่มีสัญญา sentinel/intent/handoff ที่มีรูปทรงเหมือนไฟล์ - แคชซิงก์ของ Matrix, เมทาดาทาของที่เก็บ, การผูกเธรด, marker การตัดซ้ำขาเข้า,
สถานะ cooldown ของการตรวจสอบตอนเริ่มต้น, สแนปช็อต crypto ของ SDK IndexedDB,
ข้อมูลประจำตัว, และคีย์กู้คืน ตอนนี้ใช้ตารางสถานะ/blob ของ Plugin ใน SQLite ร่วม
struct พาธของรันไทม์ไม่เปิดเผยพาธเมทาดาทา
storage-meta.jsonอีกต่อไป; ชื่อไฟล์นั้นเป็นเพียงอินพุตสำหรับการย้ายข้อมูลดั้งเดิมเท่านั้น แผนการนำเข้า JSON ดั้งเดิมของสิ่งเหล่านี้ อยู่ในพื้นผิว setup/doctor migration ของ Plugin Matrix - การเริ่มต้นของ Matrix ไม่สแกน รายงาน หรือทำให้สถานะไฟล์ Matrix ดั้งเดิมเสร็จสมบูรณ์อีกต่อไป การตรวจหาไฟล์ Matrix, การสร้างสแนปช็อต crypto ดั้งเดิม, สถานะการย้ายข้อมูล restore ของ room-key, การนำเข้า, และการลบแหล่งที่มา ล้วนเป็นหน้าที่ของ doctor
- barrel การย้ายข้อมูลของรันไทม์ Matrix ถูกลบแล้ว helper สำหรับการตรวจหาและแก้ไขสถานะ/crypto ดั้งเดิม ถูกนำเข้าโดย Matrix doctor โดยตรง แทนการเป็นส่วนหนึ่งของพื้นผิว API ของรันไทม์
- marker การนำสแนปช็อตการย้ายข้อมูลของ Matrix กลับมาใช้ซ้ำตอนนี้อยู่ในสถานะ Plugin ของ SQLite
แทน
matrix/migration-snapshot.json; doctor ยังสามารถนำ archive ก่อนย้ายข้อมูลที่ตรวจสอบแล้วชุดเดิม กลับมาใช้ซ้ำได้โดยไม่ต้องเขียนไฟล์สถานะ sidecar - cursor ของบัส Nostr และสถานะการเผยแพร่โปรไฟล์ตอนนี้ใช้สถานะ Plugin ของ SQLite ร่วม แผนการนำเข้า JSON ดั้งเดิมของสิ่งเหล่านี้อยู่ในพื้นผิว setup/doctor migration ของ Plugin Nostr
- toggle เซสชันของ Active Memory ตอนนี้ใช้สถานะ Plugin ของ SQLite ร่วมแทน
session-toggles.json; การเปิด memory กลับมาอีกครั้งจะลบแถวแทนการเขียนวัตถุ JSON ซ้ำ - ข้อเสนอของ Skill Workshop และตัวนับรีวิวตอนนี้ใช้สถานะ Plugin ของ SQLite ร่วม
แทน store
skill-workshop/<workspace>.jsonต่อ workspace แต่ละข้อเสนอเป็นแถวแยก ภายใต้skill-workshop/proposalsและตัวนับรีวิวเป็นแถวแยกภายใต้skill-workshop/reviews - การรัน subagent ของผู้รีวิว Skill Workshop ตอนนี้ใช้ตัวแก้ไข transcript เซสชันของรันไทม์
แทนการสร้างพาธเซสชัน sidecar
skill-workshop/<sessionId>.json - lease ของกระบวนการ ACPX ตอนนี้ใช้สถานะ Plugin ของ SQLite ร่วมภายใต้
acpx/process-leasesแทน registry ทั้งไฟล์process-leases.jsonแต่ละ lease ถูกจัดเก็บเป็นแถวของตัวเอง โดยยังคงการเก็บกวาดกระบวนการค้างตอนเริ่มต้น โดยไม่มีพาธเขียน JSON ซ้ำในรันไทม์ - สคริปต์ wrapper ของ ACPX และ home ของ Codex แบบแยกโดดถูกสร้างใน temp root ของ OpenClaw สิ่งเหล่านี้จะถูกสร้างใหม่ตามต้องการและไม่ใช่อินพุตสำหรับ backup หรือ migration
- persistence ของ registry การรัน subagent ใช้แถว
subagent_runsร่วมแบบมีชนิดกำกับ พาธเก่าsubagents/runs.jsonตอนนี้เป็นเพียงอินพุตสำหรับการย้ายข้อมูลของ doctor และ ชื่อ helper ของรันไทม์ไม่อธิบายเลเยอร์สถานะว่าเป็น disk-backed อีกต่อไป การทดสอบรันไทม์ไม่สร้าง fixtureruns.jsonที่ไม่ถูกต้องหรือว่างเปล่าเพื่อพิสูจน์ พฤติกรรม registry อีกต่อไป; แต่ seed/read แถว SQLite โดยตรง - Backup staging ไดเรกทอรีสถานะก่อนทำ archive, คัดลอกไฟล์ที่ไม่ใช่ฐานข้อมูล,
snapshot ฐานข้อมูล
*.sqliteด้วยVACUUM INTO, ละเว้น sidecar WAL/SHM สด, บันทึกเมทาดาทาสแนปช็อตใน manifest ของ archive, และบันทึก การรัน backup ที่เสร็จสมบูรณ์ใน SQLite พร้อม manifest ของ archiveopenclaw backup createตรวจสอบ archive ที่เขียนแล้วเป็นค่าเริ่มต้น;--no-verifyคือ fast path แบบชัดเจน openclaw backup restoreตรวจสอบ archive ก่อนแตกไฟล์ ใช้ manifest ที่ normalize แล้วของ verifier ซ้ำ และกู้คืน asset ใน manifest ที่ตรวจสอบแล้วไปยังพาธต้นทางที่บันทึกไว้ ต้องใช้--yesสำหรับการเขียน และรองรับ--dry-runสำหรับแผน restore- ตัวกรอง volatile-path ของ backup แบบเก่าถูกลบแล้ว Backup ไม่ต้องใช้ live-tar skip list สำหรับไฟล์ JSON/JSONL ของเซสชันหรือ cron ดั้งเดิมอีกต่อไป เพราะสแนปช็อต SQLite ถูก staging ก่อนสร้าง archive
- การเตรียม workspace สำหรับ setup และ onboarding แบบธรรมดาไม่สร้างไดเรกทอรี
agents/<agentId>/sessions/อีกต่อไป สิ่งเหล่านี้สร้างเฉพาะ config/workspace; แถวเซสชัน SQLite และแถว transcript จะถูกสร้างตามต้องการใน ฐานข้อมูลต่อ agent - การซ่อมสิทธิ์ด้านความปลอดภัยตอนนี้มุ่งไปที่ฐานข้อมูล SQLite ระดับ global และต่อ agent
รวมถึง sidecar WAL/SHM แทน
sessions.jsonและไฟล์ transcript JSONL - ชื่อรันไทม์ของ sandbox registry ตอนนี้อธิบายชนิด registry ของ SQLite โดยตรง แทนการพกคำศัพท์ registry JSON ดั้งเดิมผ่าน active store
openclaw reset --scope config+creds+sessionsลบฐานข้อมูลopenclaw-agent.sqliteต่อ agent รวมถึง sidecar WAL/SHM ไม่ใช่เพียง ไดเรกทอรีsessions/ดั้งเดิม- helper เซสชันรวมของ Gateway ตอนนี้ใช้ชื่อที่เน้น entry:
loadCombinedSessionEntriesForGatewayคืนค่า{ databasePath, entries }การตั้งชื่อ combined-store แบบเก่าถูกลบออกจาก caller ของรันไทม์แล้ว - การ seed ช่อง Docker MCP ตอนนี้เขียนแถวเซสชันหลักและเหตุการณ์ transcript
ลงในฐานข้อมูล SQLite ต่อ agent แทนการสร้าง
sessions.jsonและ transcript แบบ JSONL - hook session-memory ที่ bundle มา ตอนนี้แก้ไข context ของเซสชันก่อนหน้าจาก
SQLite ด้วย
{agentId, sessionId}และไม่สแกน จัดเก็บ หรือสังเคราะห์ พาธ transcript หรือไดเรกทอรีworkspace/sessionsอีกต่อไป - hook command-logger ที่ bundle มา ตอนนี้เขียนแถว audit ของคำสั่งไปยังตาราง SQLite ร่วม
command_log_entriesแทนการ appendlogs/commands.log - allowlist การจับคู่ช่องตอนนี้เปิดเผยเฉพาะ helper อ่าน/เขียนที่มี SQLite หนุนหลัง
ในรันไทม์และใน Plugin SDK ตัวแก้ไขพาธ
*-allowFrom.jsonแบบเก่าและ file reader อยู่เฉพาะภายใต้โค้ดนำเข้า legacy ของ doctor migration_runsบันทึกการดำเนินการย้ายข้อมูลสถานะดั้งเดิมพร้อมสถานะ timestamp และรายงาน JSONmigration_sourcesบันทึกแหล่งไฟล์ดั้งเดิมแต่ละไฟล์ที่นำเข้า พร้อม hash, size, จำนวน record, ตารางปลายทาง, run id, สถานะ, และสถานะการลบแหล่งที่มาbackup_runsบันทึกพาธ archive ของ backup, สถานะ, และ manifest JSON- schema ระดับ global ไม่เก็บตาราง registry
agentsที่ไม่ได้ใช้ การค้นพบ ฐานข้อมูล agent คือ registryagent_databasesที่เป็น canonical จนกว่ารันไทม์ จะมีเจ้าของ agent-record จริง - config ของ model catalog ที่สร้างขึ้นถูกจัดเก็บในแถว SQLite ระดับ global แบบมีชนิดกำกับ
agent_model_catalogsโดยใช้ไดเรกทอรี agent เป็นคีย์ caller ของรันไทม์ใช้ensureOpenClawModelCatalog; ไม่มี API compatibility สำหรับmodels.jsonใน โค้ดรันไทม์ implementation เขียน SQLite และ embedded PI registry ถูก hydrate จาก payload ที่จัดเก็บไว้นั้นโดยไม่สร้างไฟล์models.json - การ export markdown transcript เซสชันของ QMD และ config
memory.qmd.sessionsถูกลบแล้ว ไม่มีคอลเลกชัน transcript ของ QMD, ไม่มีพาธรันไทม์qmd/sessions*, และไม่มี bridge memory ของเซสชันที่มีไฟล์หนุนหลัง - รันไทม์ memory-core นำเข้า helper การทำดัชนี transcript ของ SQLite จาก
openclaw/plugin-sdk/memory-core-host-engine-session-transcriptsไม่ใช่ subpath ของ QMD SDK subpath ของ QMD เก็บ compatibility re-export ไว้เฉพาะสำหรับ caller ภายนอกจนกว่าการ cleanup SDK รุ่น major จะลบออกได้ index.sqliteของ QMD เองตอนนี้เป็นการ materialization ชั่วคราวของรันไทม์ที่หนุนหลังโดย ตาราง SQLite หลักplugin_blob_entriesรันไทม์ไม่สร้าง sidecar ถาวร~/.openclaw/agents/<agentId>/qmdอีกต่อไป- Plugin
memory-lancedbแบบไม่บังคับไม่สร้าง~/.openclaw/memory/lancedbเป็น store ที่ OpenClaw จัดการโดยนัยอีกต่อไป มันเป็น backend LanceDB ภายนอกและยังคงปิดใช้งานจนกว่าผู้ปฏิบัติงานจะกำหนดค่าdbPathอย่างชัดเจน check:database-first-legacy-storesทำให้ source รันไทม์ใหม่ที่จับคู่ ชื่อ store ดั้งเดิมกับ API ระบบไฟล์แบบเขียนล้มเหลว และยังทำให้ source รันไทม์ ที่นำ marker bridge transcript ที่ปลดระวางแล้วกลับมาใช้ใหม่transcriptLocatorหรือsqlite-transcript://...ล้มเหลว โค้ด migration, doctor, import, และ non-session export แบบชัดเจนยังคงได้รับอนุญาต ชื่อสัญญาดั้งเดิมที่กว้างกว่า เช่นsessionFile,storePath, และ facade ยุคไฟล์ของSessionManagerเก่า ยังมีเจ้าของปัจจุบันและต้องมีงาน guard การย้ายข้อมูลแยกต่างหาก ก่อนจะกลายเป็นการตรวจ preflight ที่จำเป็นได้ guard ตอนนี้ยังครอบคลุม storecache/*.jsonของรันไทม์, sidecarthread-bindings.jsonแบบทั่วไป, JSON ของสถานะ cron/run-log, JSON ของ config health, sidecar restart และ lock, การตั้งค่า Voice Wake, การอนุมัติการผูก Plugin, JSON ของดัชนี Plugin ที่ติดตั้งแล้ว, audit JSONL ของ File Transfer, activity log ของ Memory Wiki, text logcommand-loggerที่ bundle มาแบบเก่า, และ knob diagnostics JSONL ของ pi-mono raw-stream และยังแบนชื่อโมดูล legacy ของ doctor ระดับ root แบบเก่า เพื่อให้ โค้ด compatibility อยู่ภายใต้src/commands/doctor/handler debug ของ Android ยังใช้ logcat/เอาต์พุตในหน่วยความจำแทนการ staging ไฟล์แคชcamera_debug.logหรือdebug_logs.txt
รูปแบบสคีมาเป้าหมาย
รักษาสคีมาให้ชัดเจน สถานะรันไทม์ที่โฮสต์เป็นเจ้าของใช้ตารางที่มีชนิดข้อมูลกำกับ สถานะทึบที่ Plugin เป็นเจ้าของใช้ plugin_state_entries / plugin_blob_entries; ไม่มีตาราง kv ทั่วไปของโฮสต์
ฐานข้อมูลส่วนกลาง:
state_leases(scope, lease_key, owner, expires_at, heartbeat_at, payload_json, created_at, updated_at)exec_approvals_config(config_key, raw_json, socket_path, has_socket_token, default_security, default_ask, default_ask_fallback, auto_allow_skills, agent_count, allowlist_count, updated_at_ms)schema_meta(meta_key, role, schema_version, agent_id, app_version, created_at, updated_at)agent_databases(agent_id, path, schema_version, last_seen_at, size_bytes)task_runs(...)task_delivery_state(...)flow_runs(...)subagent_runs(run_id, child_session_key, requester_session_key, controller_session_key, created_at, ended_at, cleanup_handled, payload_json)current_conversation_bindings(binding_key, binding_id, target_agent_id, target_session_id, target_session_key, channel, account_id, conversation_kind, parent_conversation_id, conversation_id, target_kind, status, bound_at, expires_at, metadata_json, updated_at)plugin_binding_approvals(plugin_root, channel, account_id, plugin_id, plugin_name, approved_at)tui_last_sessions(scope_key, session_key, updated_at)plugin_state_entries(plugin_id, namespace, entry_key, value_json, created_at, expires_at)plugin_blob_entries(plugin_id, namespace, entry_key, metadata_json, blob, created_at, expires_at)media_blobs(subdir, id, content_type, size_bytes, blob, created_at, updated_at)skill_uploads(upload_id, kind, slug, force, size_bytes, sha256, actual_sha256, received_bytes, archive_blob, created_at, expires_at, committed, committed_at, idempotency_key_hash)web_push_subscriptions(endpoint_hash, subscription_id, endpoint, p256dh, auth, created_at_ms, updated_at_ms)web_push_vapid_keys(key_id, public_key, private_key, subject, updated_at_ms)apns_registrations(node_id, transport, token, relay_handle, send_grant, installation_id, topic, environment, distribution, token_debug_suffix, updated_at_ms)node_host_config(config_key, version, node_id, token, display_name, gateway_host, gateway_port, gateway_tls, gateway_tls_fingerprint, updated_at_ms)device_identities(identity_key, device_id, public_key_pem, private_key_pem, created_at_ms, updated_at_ms)device_auth_tokens(device_id, role, token, scopes_json, updated_at_ms)macos_port_guardian_records(pid, port, command, mode, timestamp)workspace_setup_state(workspace_key, workspace_path, version, bootstrap_seeded_at, setup_completed_at, updated_at)native_hook_relay_bridges(relay_id, pid, hostname, port, token, expires_at_ms, updated_at_ms)model_capability_cache(provider_id, model_id, name, input_text, input_image, reasoning, supports_tools, context_window, max_tokens, cost_input, cost_output, cost_cache_read, cost_cache_write, updated_at_ms)agent_model_catalogs(catalog_key, agent_dir, raw_json, updated_at)managed_outgoing_image_records(attachment_id, session_key, message_id, created_at, updated_at, retention_class, alt, original_media_id, original_media_subdir, original_content_type, original_width, original_height, original_size_bytes, original_filename, record_json)gateway_restart_sentinel(sentinel_key, version, kind, status, ts, session_key, thread_id, delivery_channel, delivery_to, delivery_account_id, message, continuation_json, doctor_hint, stats_json, payload_json, updated_at_ms)channel_pairing_requests(channel_key, account_id, request_id, code, created_at, last_seen_at, meta_json)channel_pairing_allow_entries(channel_key, account_id, entry, sort_order, updated_at)voicewake_triggers(config_key, position, trigger, updated_at_ms)voicewake_routing_config(config_key, version, default_target_mode, default_target_agent_id, default_target_session_key, updated_at_ms)voicewake_routing_routes(config_key, position, trigger, target_mode, target_agent_id, target_session_key, updated_at_ms)update_check_state(state_key, last_checked_at, last_notified_version, last_notified_tag, last_available_version, last_available_tag, auto_install_id, auto_first_seen_version, auto_first_seen_tag, auto_first_seen_at, auto_last_attempt_version, auto_last_attempt_at, auto_last_success_version, auto_last_success_at, updated_at_ms)config_health_entries(config_path, last_known_good_json, last_promoted_good_json, last_observed_suspicious_signature, updated_at_ms)sandbox_registry_entries(registry_kind, container_name, session_key, backend_id, runtime_label, image, created_at_ms, last_used_at_ms, config_label_kind, config_hash, cdp_port, no_vnc_port, entry_json, updated_at)cron_run_logs(store_key, job_id, seq, ts, status, error, summary, diagnostics_summary, delivery_status, delivery_error, delivered, session_id, session_key, run_id, run_at_ms, duration_ms, next_run_at_ms, model, provider, total_tokens, entry_json, created_at)cron_jobs(store_key, job_id, name, description, enabled, delete_after_run, created_at_ms, agent_id, session_key, schedule_kind, schedule_expr, schedule_tz, every_ms, anchor_ms, at, stagger_ms, session_target, wake_mode, payload_kind, payload_message, payload_model, payload_fallbacks_json, payload_thinking, payload_timeout_seconds, payload_allow_unsafe_external_content, payload_external_content_source_json, payload_light_context, payload_tools_allow_json, delivery_mode, delivery_channel, delivery_to, delivery_thread_id, delivery_account_id, delivery_best_effort, failure_delivery_mode, failure_delivery_channel, failure_delivery_to, failure_delivery_account_id, failure_alert_disabled, failure_alert_after, failure_alert_channel, failure_alert_to, failure_alert_cooldown_ms, failure_alert_include_skipped, failure_alert_mode, failure_alert_account_id, next_run_at_ms, running_at_ms, last_run_at_ms, last_run_status, last_error, last_duration_ms, consecutive_errors, consecutive_skipped, schedule_error_count, last_delivery_status, last_delivery_error, last_delivered, last_failure_alert_at_ms, job_json, state_json, runtime_updated_at_ms, schedule_identity, sort_order, updated_at)delivery_queue_entries(queue_name, id, status, entry_kind, session_key, channel, target, account_id, retry_count, last_attempt_at, last_error, recovery_state, platform_send_started_at, entry_json, enqueued_at, updated_at, failed_at)commitments(id, agent_id, session_key, channel, account_id, recipient_id, thread_id, sender_id, kind, sensitivity, source, status, reason, suggested_text, dedupe_key, confidence, due_earliest_ms, due_latest_ms, due_timezone, source_message_id, source_run_id, created_at_ms, updated_at_ms, attempts, last_attempt_at_ms, sent_at_ms, dismissed_at_ms, snoozed_until_ms, expired_at_ms, record_json)migration_runs(id, started_at, finished_at, status, report_json)migration_sources(source_key, migration_kind, source_path, target_table, source_sha256, source_size_bytes, source_record_count, last_run_id, status, imported_at, removed_source, report_json)backup_runs(id, created_at, archive_path, status, manifest_json)ฐานข้อมูล Agent:
schema_meta(meta_key, role, schema_version, agent_id, app_version, created_at, updated_at)sessions(session_id, session_key, session_scope, created_at, updated_at, started_at, ended_at, status, chat_type, channel, account_id, primary_conversation_id, model_provider, model, agent_harness_id, parent_session_key, spawned_by, display_name)conversations(conversation_id, channel, account_id, kind, peer_id, parent_conversation_id, thread_id, native_channel_id, native_direct_user_id, label, metadata_json, created_at, updated_at)session_conversations(session_id, conversation_id, role, first_seen_at, last_seen_at)session_routes(session_key, session_id, updated_at)session_entries(session_id, session_key, entry_json, updated_at)transcript_events(session_id, seq, event_json, created_at)transcript_event_identities(session_id, event_id, seq, event_type, has_parent, parent_id, message_idempotency_key, created_at)transcript_snapshots(session_id, snapshot_id, reason, event_count, created_at, metadata_json)vfs_entries(namespace, path, kind, content_blob, metadata_json, updated_at)tool_artifacts(run_id, artifact_id, kind, metadata_json, blob, created_at)run_artifacts(run_id, path, kind, metadata_json, blob, created_at)trajectory_runtime_events(session_id, run_id, seq, event_json, created_at)memory_index_meta(key, value)memory_index_sources(path, source, hash, mtime, size)memory_index_chunks(id, path, source, start_line, end_line, hash, model, text, embedding, updated_at)memory_embedding_cache(provider, model, provider_key, hash, embedding, dims, updated_at)memory_index_state(id, revision)cache_entries(scope, key, value_json, blob, expires_at, updated_at)การค้นหาในอนาคตสามารถเพิ่มตาราง FTS ได้โดยไม่ต้องเปลี่ยนตารางเหตุการณ์มาตรฐาน:
transcript_events_fts(session_id, seq, text)vfs_entries_fts(namespace, path, text)ค่าขนาดใหญ่ควรใช้คอลัมน์ blob ไม่ใช่การเข้ารหัสเป็นสตริง JSON เก็บ value_json ไว้สำหรับข้อมูลเชิงโครงสร้างขนาดเล็กที่ต้องยังตรวจสอบได้ด้วยเครื่องมือ SQLite แบบธรรมดา
agent_databases คือ registry มาตรฐานสำหรับบรานช์นี้ อย่าเพิ่มตาราง agents จนกว่าจะมีเจ้าของเรคคอร์ด Agent จริง; การกำหนดค่า Agent ยังคงอยู่ใน openclaw.json
รูปแบบการย้ายข้อมูลของ Doctor
Doctor ควรเรียกขั้นตอนการย้ายข้อมูลที่ชัดเจนเพียงขั้นตอนเดียว ซึ่งรายงานได้และรันซ้ำได้อย่างปลอดภัย:
openclaw doctor --fixopenclaw doctor --fix เรียกใช้การย้ายข้อมูลสถานะหลังจากการตรวจล่วงหน้าการกำหนดค่าตามปกติ และสร้างข้อมูลสำรองที่ตรวจยืนยันแล้วก่อนนำเข้า การเริ่มต้นรันไทม์และ openclaw migrate ต้องไม่นำเข้าไฟล์สถานะ OpenClaw รุ่นเก่า
คุณสมบัติของการย้ายข้อมูล:
- การย้ายข้อมูลหนึ่งรอบจะค้นพบแหล่งไฟล์รุ่นเก่าทั้งหมดและสร้างแผนก่อนแก้ไขสิ่งใด
- Doctor สร้างอาร์ไคฟ์สำรองก่อนย้ายข้อมูลที่ตรวจยืนยันแล้วก่อนนำเข้าไฟล์รุ่นเก่า
- การนำเข้าเป็นแบบ idempotent และใช้พาธแหล่งที่มา, mtime, ขนาด, แฮช และตารางเป้าหมายเป็นคีย์
- ไฟล์แหล่งที่มาที่สำเร็จจะถูกลบหรือเก็บถาวรหลังจากฐานข้อมูลเป้าหมาย commit แล้ว
- การนำเข้าที่ล้มเหลวจะปล่อยแหล่งที่มาไว้เหมือนเดิมและบันทึกคำเตือนใน
migration_runs - โค้ดรันไทม์อ่านเฉพาะ SQLite หลังจากมีการย้ายข้อมูลแล้ว
- ไม่จำเป็นต้องมีเส้นทาง downgrade/export-to-runtime-files
บัญชีรายการการย้ายข้อมูล
ย้ายสิ่งเหล่านี้เข้าสู่ฐานข้อมูลส่วนกลาง:
- การเขียนขณะรันของรีจิสทรีงานตอนนี้ใช้ฐานข้อมูลที่ใช้ร่วมกันแล้ว; ตัวนำเข้าไฟล์ข้างเคียง
tasks/runs.sqliteที่ยังไม่เคยจัดส่งถูกลบแล้ว การบันทึกสแนปช็อตทำ upsert ตาม id ของงาน และลบเฉพาะแถวงาน/การส่งมอบที่หายไปเท่านั้น - การเขียนขณะรันของ Task Flow ตอนนี้ใช้ฐานข้อมูลที่ใช้ร่วมกันแล้ว; ตัวนำเข้าไฟล์ข้างเคียง
tasks/flows/registry.sqliteที่ยังไม่เคยจัดส่งถูกลบแล้ว การบันทึกสแนปช็อต ทำ upsert ตาม flow id และลบเฉพาะแถว flow ที่หายไปเท่านั้น - การเขียนขณะรันของสถานะ Plugin ตอนนี้ใช้ฐานข้อมูลที่ใช้ร่วมกันแล้ว; ตัวนำเข้าไฟล์ข้างเคียง
plugin-state/state.sqliteที่ยังไม่เคยจัดส่งถูกลบแล้ว - การค้นหาหน่วยความจำในตัวไม่ใช้ค่าเริ่มต้นเป็น
memory/<agentId>.sqliteอีกต่อไป; ตาราง ดัชนีของมันอยู่ในฐานข้อมูลของเอเจนต์เจ้าของ และการเลือกใช้ไฟล์ข้างเคียงแบบชัดเจนผ่านmemorySearch.store.pathถูกเลิกใช้และย้ายไปอยู่ในการย้ายข้อมูลคอนฟิกของ doctor แล้ว - การทำดัชนีใหม่ของหน่วยความจำในตัวรีเซ็ตเฉพาะตารางที่หน่วยความจำเป็นเจ้าของในฐานข้อมูลเอเจนต์ เท่านั้น ต้องไม่แทนที่ไฟล์ SQLite ทั้งไฟล์ เพราะฐานข้อมูลเดียวกันนี้เป็นเจ้าของ เซสชัน ทรานสคริปต์ แถว VFS อาร์ทิแฟกต์ และแคชขณะรัน
- รีจิสทรีคอนเทนเนอร์/เบราว์เซอร์ Sandbox จาก JSON แบบโมโนลิทิกและแบบแบ่งชาร์ด การเขียน ขณะรันตอนนี้ใช้ฐานข้อมูลที่ใช้ร่วมกันแล้ว; การนำเข้า JSON เดิมยังคงอยู่
- นิยามงาน Cron, สถานะกำหนดการ และประวัติการรัน ตอนนี้ใช้ SQLite ที่ใช้ร่วมกัน;
doctor นำเข้า/ลบไฟล์เดิม
jobs.json,jobs-state.jsonและcron/runs/*.jsonl - ตัวตน/การยืนยันตัวตนของอุปกรณ์, push, การตรวจอัปเดต, commitments, แคชโมเดล OpenRouter, ดัชนี Plugin ที่ติดตั้ง และการผูก app-server
- ระเบียนการจับคู่และ bootstrap ของอุปกรณ์/Node ตอนนี้ใช้ตาราง SQLite แบบมีชนิด
- ผู้สมัครรับการแจ้งเตือน device-pair และตัวทำเครื่องหมาย delivered-request ตอนนี้ใช้ตาราง
plugin-state ของ SQLite ที่ใช้ร่วมกันแทน
device-pair-notify.json - ระเบียนสายโทรด้วยเสียงตอนนี้ใช้ตาราง plugin-state ของ SQLite ที่ใช้ร่วมกันภายใต้ namespace
voice-call/callsแทนcalls.jsonl; CLI ของ Plugin tail และสรุปประวัติสาย ที่มี SQLite หนุนหลัง - เซสชัน Gateway ของ QQBot, ระเบียน known-user และแคชคำอ้างอิง ref-index ตอนนี้ใช้สถานะ
Plugin ของ SQLite ภายใต้ namespace ของ
qqbot(sessions,known-users,ref-index) แทนsession-*.json,known-users.jsonและref-index.jsonl; การย้ายข้อมูล doctor/setup ของ QQBot นำเข้าและลบไฟล์เดิม - ค่ากำหนดตัวเลือกโมเดลของ Discord, แฮช command-deploy และการผูกเธรด
ตอนนี้ใช้สถานะ Plugin ของ SQLite ภายใต้ namespace ของ
discord(model-picker-preferences,command-deploy-hashes,thread-bindings) แทนmodel-picker-preferences.json,command-deploy-cache.jsonและthread-bindings.json; การย้ายข้อมูล doctor/setup ของ Discord นำเข้าและ ลบไฟล์เดิม - เคอร์เซอร์ catchup และตัวทำเครื่องหมาย dedupe ขาเข้าของ BlueBubbles ตอนนี้ใช้สถานะ Plugin
ของ SQLite ภายใต้ namespace ของ
bluebubbles(catchup-cursors,inbound-dedupe) แทนbluebubbles/catchup/*.jsonและbluebubbles/inbound-dedupe/*.json; การย้ายข้อมูล doctor/setup ของ BlueBubbles นำเข้าและลบไฟล์เดิม - ออฟเซ็ตอัปเดตของ Telegram, รายการแคชสติกเกอร์, รายการแคชข้อความ reply-chain,
รายการแคช sent-message, รายการแคชชื่อหัวข้อ และการผูกเธรด
ตอนนี้ใช้สถานะ Plugin ของ SQLite ภายใต้ namespace ของ
telegram(update-offsets,sticker-cache,message-cache,sent-messages,topic-names,thread-bindings) แทนupdate-offset-*.json,sticker-cache.json,*.telegram-messages.json,*.telegram-sent-messages.json,*.telegram-topic-names.jsonและthread-bindings-*.json; การย้ายข้อมูล doctor/setup ของ Telegram นำเข้าและ ลบไฟล์เดิม - เคอร์เซอร์ catchup ของ iMessage, การแมป short-id ของ reply และแถว dedupe sent-echo
ตอนนี้ใช้สถานะ Plugin ของ SQLite ภายใต้ namespace ของ
imessage(catchup-cursors,reply-cache,sent-echoes) แทนimessage/catchup/*.json,imessage/reply-cache.jsonlและimessage/sent-echoes.jsonl; การย้ายข้อมูล doctor/setup ของ iMessage นำเข้าและลบไฟล์เดิม - บทสนทนา, โพล, โทเค็น SSO และ feedback learnings ของ Microsoft Teams ตอนนี้
ใช้ namespace สถานะ Plugin ของ SQLite (
conversations,polls,sso-tokens,feedback-learnings) แทนmsteams-conversations.json,msteams-polls.json,msteams-sso-tokens.jsonและ*.learnings.json; การย้ายข้อมูล doctor/setup ของ Microsoft Teams นำเข้าและเก็บถาวรไฟล์เดิม การอัปโหลดที่รอดำเนินการเป็นแคช SQLite อายุสั้น และไฟล์แคช JSON เก่า จะไม่ถูกย้ายข้อมูล - แคชซิงก์ของ Matrix, เมทาดาทาพื้นที่จัดเก็บ, การผูกเธรด, ตัวทำเครื่องหมาย dedupe ขาเข้า,
สถานะ cooldown สำหรับการตรวจสอบตอนเริ่มต้น, ข้อมูลประจำตัว, คีย์กู้คืน และสแนปช็อตคริปโต
IndexedDB ของ SDK ตอนนี้ใช้ namespace สถานะ/blob ของ Plugin ใน SQLite ภายใต้
matrix(sync-store,storage-meta,thread-bindings,inbound-dedupe,startup-verification,credentials,recovery-key,idb-snapshots) แทนbot-storage.json,storage-meta.json,thread-bindings.json,inbound-dedupe.json,startup-verification.json,credentials.json,recovery-key.jsonและcrypto-idb-snapshot.json; การย้ายข้อมูล doctor/setup ของ Matrix นำเข้าและลบไฟล์เดิมเหล่านั้นจากรากพื้นที่จัดเก็บ Matrix ที่กำหนดขอบเขตตามบัญชี - เคอร์เซอร์บัสและสถานะการเผยแพร่โปรไฟล์ของ Nostr ตอนนี้ใช้สถานะ Plugin ของ SQLite ภายใต้
namespace ของ
nostr(bus-state,profile-state) แทนbus-state-*.jsonและprofile-state-*.json; การย้ายข้อมูล doctor/setup ของ Nostr นำเข้าและลบไฟล์เดิม - ตัวสลับเซสชันของ Active Memory ตอนนี้ใช้สถานะ Plugin ของ SQLite ภายใต้
active-memory/session-togglesแทนsession-toggles.json - คิวข้อเสนอและตัวนับรีวิวของ Skill Workshop ตอนนี้ใช้สถานะ Plugin ของ SQLite
ภายใต้
skill-workshop/proposalsและskill-workshop/reviewsแทน ไฟล์skill-workshop/<workspace>.jsonต่อ workspace - คิวการส่งมอบขาออกและการส่งมอบเซสชันตอนนี้ใช้ตาราง SQLite ส่วนกลาง
delivery_queue_entriesร่วมกัน ภายใต้ชื่อคิวที่แยกกัน (outbound-delivery,session-delivery) แทนไฟล์ที่คงทนdelivery-queue/*.json,delivery-queue/failed/*.jsonและsession-delivery-queue/*.jsonขั้นตอน legacy-state ของ doctor นำเข้า แถวที่รอดำเนินการและล้มเหลว ลบตัวทำเครื่องหมาย delivered ที่ค้างอยู่ และลบไฟล์ JSON เก่าหลังนำเข้า ฟิลด์ hot routing และ retry เป็นคอลัมน์แบบมีชนิด; เพย์โหลด JSON ถูกเก็บไว้เฉพาะเพื่อ replay/debug เท่านั้น - สัญญาเช่ากระบวนการ ACPX ตอนนี้ใช้สถานะ Plugin ของ SQLite ภายใต้
acpx/process-leasesแทนprocess-leases.json - เมทาดาทาการรันสำรองและการย้ายข้อมูล
ย้ายรายการเหล่านี้ไปยังฐานข้อมูลเอเจนต์:
- รากเซสชันเอเจนต์และเพย์โหลด session-entry รูปทรงที่เข้ากันได้ ดำเนินการแล้วสำหรับ
การเขียนขณะรัน: เมทาดาทาเซสชันร้อนสามารถ query ได้ใน
sessionsขณะที่เพย์โหลดSessionEntryเต็มรูปทรงเดิมยังคงอยู่ในsession_entries - เหตุการณ์ทรานสคริปต์เอเจนต์ ดำเนินการแล้วสำหรับการเขียนขณะรัน
- เช็กพอยต์ Compaction และสแนปช็อตทรานสคริปต์ ดำเนินการแล้วสำหรับการเขียนขณะรัน:
สำเนาทรานสคริปต์ของเช็กพอยต์เป็นแถวทรานสคริปต์ใน SQLite และเมทาดาทาเช็กพอยต์
ถูกบันทึกใน
transcript_snapshotsตัวช่วยเช็กพอยต์ของ Gateway ตอนนี้เรียกค่าเหล่านี้ว่า สแนปช็อตทรานสคริปต์แทนไฟล์ต้นทาง - namespace scratch/workspace ของ VFS เอเจนต์ ดำเนินการแล้วสำหรับการเขียน VFS ขณะรัน
- เพย์โหลดไฟล์แนบของ subagent ดำเนินการแล้วสำหรับการเขียนขณะรัน: สิ่งเหล่านี้เป็นรายการ seed ของ SQLite VFS และไม่ใช่ไฟล์ workspace ที่คงทนอีกต่อไป
- อาร์ทิแฟกต์เครื่องมือ ดำเนินการแล้วสำหรับการเขียนขณะรัน
- อาร์ทิแฟกต์การรัน ดำเนินการแล้วสำหรับการเขียนขณะรันของ worker ผ่านตาราง
run_artifactsต่อเอเจนต์ - แคชขณะรันแบบ local ของเอเจนต์ ดำเนินการแล้วสำหรับการเขียนแคชขณะรันของ worker
ที่กำหนดขอบเขตผ่านตาราง
cache_entriesต่อเอเจนต์ แคชโมเดลระดับ Gateway ยังคงอยู่ในฐานข้อมูลส่วนกลาง เว้นแต่มันจะกลายเป็นข้อมูลเฉพาะเอเจนต์ - บันทึกสตรีมแม่ของ ACP ดำเนินการแล้วสำหรับการเขียนขณะรัน
- เซสชันบัญชีแยกประเภท replay ของ ACP ดำเนินการแล้วสำหรับการเขียนขณะรันผ่าน
acp_replay_sessionsและacp_replay_events;acp/event-ledger.jsonเดิมยังคงอยู่เฉพาะในฐานะอินพุตของ doctor - เมทาดาทาเซสชัน ACP ดำเนินการแล้วสำหรับการเขียนขณะรันผ่าน
acp_sessions; บล็อกentry.acpเดิมในsessions.jsonเป็นอินพุตการย้ายข้อมูลของ doctor เท่านั้น - ไฟล์ข้างเคียง trajectory เมื่อไม่ใช่ไฟล์ส่งออกแบบชัดเจน ดำเนินการแล้วสำหรับการเขียน
ขณะรัน: การจับ trajectory เขียนแถว
trajectory_runtime_eventsในฐานข้อมูลเอเจนต์ และ mirror อาร์ทิแฟกต์ที่กำหนดขอบเขตตาม run เข้า SQLite ไฟล์ข้างเคียงเดิมเป็นอินพุต นำเข้าของ doctor เท่านั้น; export สามารถสร้างเอาต์พุต support-bundle JSONL ใหม่ได้ แต่ไม่อ่านหรือย้ายข้อมูลไฟล์ข้างเคียง trajectory/transcript เก่าขณะรัน การจับ trajectory ขณะรันเปิดเผย scope ของ SQLite; ตัวช่วยพาธ JSONL ถูกแยกไว้สำหรับ การสนับสนุน export/debug และไม่ถูก re-export จากโมดูล runtime เมทาดาทา trajectory ของ embedded-runner บันทึกตัวตน{agentId, sessionId, sessionKey}แทนการคงอยู่ของตัวระบุตำแหน่งทรานสคริปต์
คงรายการเหล่านี้ให้มีไฟล์หนุนหลังไว้ก่อน:
openclaw.json- ไฟล์ข้อมูลประจำตัวของ provider หรือ CLI
- manifest ของ Plugin/package
- workspace ของผู้ใช้และ Git repositories เมื่อเลือกโหมดดิสก์
- logs ที่ตั้งใจให้ operator tail เว้นแต่ surface ของ log เฉพาะจะถูกย้าย
แผนการย้ายข้อมูล
ระยะที่ 0: ตรึงขอบเขตให้ชัดเจน
ทำให้ขอบเขต durable-state ชัดเจนก่อนย้ายแถวเพิ่มเติม:
- เพิ่มตาราง
migration_runsลงในฐานข้อมูลส่วนกลาง ดำเนินการแล้วสำหรับรายงานการดำเนินการย้ายข้อมูล legacy-state - เพิ่มบริการย้ายสถานะที่ doctor เป็นเจ้าของเพียงบริการเดียวสำหรับการนำเข้าจากไฟล์สู่ฐานข้อมูล
ดำเนินการแล้ว:
openclaw doctor --fixใช้ implementation การย้ายข้อมูล legacy-state - ทำให้
planเป็นแบบอ่านอย่างเดียว และทำให้applyสร้างข้อมูลสำรอง นำเข้า ตรวจสอบ แล้วจึงลบหรือกักกันไฟล์เก่า ดำเนินการแล้ว: doctor สร้างข้อมูลสำรองก่อนย้ายข้อมูลที่ตรวจสอบแล้ว ส่งพาธข้อมูลสำรอง เข้าmigration_runsและใช้พาธนำเข้า/ลบซ้ำ - เพิ่มการแบนแบบ static เพื่อไม่ให้โค้ดขณะรันใหม่เขียนไฟล์สถานะเดิม ขณะที่โค้ดและการทดสอบ การย้ายข้อมูลยังสามารถ seed/read ไฟล์เหล่านั้นได้ ดำเนินการแล้วสำหรับ store เดิมที่ย้ายแล้วในปัจจุบัน; guard ยังสแกนการทดสอบที่ซ้อนกัน เพื่อหาสัญญา transcript locator ขณะรันที่ต้องห้ามด้วย
ระยะที่ 1: ทำ Control Plane ส่วนกลางให้เสร็จ
เก็บสถานะการประสานงานที่ใช้ร่วมกันไว้ใน state/openclaw.sqlite:
- เอเจนต์และรีจิสทรีฐานข้อมูลเอเจนต์
- บัญชีแยกประเภทของงานและ Task Flow
- สถานะ Plugin
- รีจิสทรีคอนเทนเนอร์/เบราว์เซอร์ Sandbox
- ประวัติการรัน Cron/scheduler
- การจับคู่, อุปกรณ์, push, update-check, TUI, แคช OpenRouter/model และสถานะขณะรันขนาดเล็กอื่นๆ ที่กำหนดขอบเขตระดับ Gateway
- เมทาดาทาสำรองและการย้ายข้อมูล
- ไบต์ไฟล์แนบสื่อของ Gateway ดำเนินการแล้วสำหรับการเขียนขณะรัน; พาธไฟล์โดยตรง
เป็นการ materialize ชั่วคราวเพื่อความเข้ากันได้กับตัวส่งของช่องทางและการ staging ของ sandbox
allowlist ขณะรันยอมรับพาธ materialization ของ SQLite ไม่ใช่ราก media ของ state/config เดิม
doctor นำเข้าไฟล์สื่อเดิมเข้าสู่
media_blobsและลบไฟล์ต้นทางหลังเขียนแถวสำเร็จ - เซสชัน, เหตุการณ์ และ blob เพย์โหลดของ debug proxy capture ดำเนินการแล้ว: capture อยู่ใน
DB สถานะที่ใช้ร่วมกัน และเปิดผ่าน bootstrap, schema, WAL และการตั้งค่า busy-timeout
ของ DB สถานะที่ใช้ร่วมกัน ไบต์เพย์โหลดถูกบีบอัดด้วย gzip ใน
capture_blobs.data; ไม่มีการ override DB ข้างเคียงขณะรันเฉพาะ debug proxy, ไดเรกทอรี blob หรือเป้าหมาย schema/codegen ที่สร้างขึ้นสำหรับ proxy-capture เท่านั้น การย้ายข้อมูล doctor/startup นำเข้าแถวdebug-proxy/capture.sqliteที่จัดส่งแล้ว และ blob เพย์โหลดที่อ้างอิง รวมถึงการ override environment ของ DB/blob เดิมที่ยังใช้งานอยู่ จากนั้นเก็บถาวรแหล่งเหล่านั้นโดยปล่อยใบรับรอง CA ไว้เหมือนเดิม
ระยะนี้ยังลบตัวเปิดไฟล์ข้างเคียงซ้ำๆ, ตัวช่วยสิทธิ์, การตั้งค่า WAL, การตัดแต่งไฟล์ซิสเต็ม และตัวเขียนความเข้ากันได้ออกจากระบบย่อยเหล่านั้นด้วย
ระยะที่ 2: เพิ่มฐานข้อมูลต่อเอเจนต์
สร้างฐานข้อมูลหนึ่งชุดต่อเอเจนต์ และลงทะเบียนจาก DB ส่วนกลาง:
~/.openclaw/state/openclaw.sqlite~/.openclaw/agents/<agentId>/agent/openclaw-agent.sqliteแถว agent_databases ส่วนกลางเก็บพาธ, เวอร์ชัน schema, timestamp last-seen
และเมทาดาทาขนาด/ความสมบูรณ์พื้นฐาน โค้ดขณะรันขอ DB เอเจนต์จากรีจิสทรี
แทนการสร้างพาธไฟล์โดยตรง
DB เอเจนต์เป็นเจ้าของ:
sessionsเป็นรูทเซสชันตามมาตรฐาน โดยมีsession_entriesเป็นตารางเพย์โหลดรูปแบบความเข้ากันได้ที่แนบกับรูทนั้น และsession_routesเป็นการค้นหาsession_keyที่ใช้งานอยู่แบบไม่ซ้ำconversationsและsession_conversationsเป็นข้อมูลระบุตัวตนการกำหนดเส้นทางผู้ให้บริการที่ทำให้เป็นมาตรฐานและแนบกับเซสชันtranscript_events- สแนปชอตทรานสคริปต์และจุดตรวจ Compaction เสร็จแล้วสำหรับการเขียนของรันไทม์
vfs_entriestool_artifactsและอาร์ติแฟกต์ของการรัน- แถวรันไทม์/แคชภายในเอเจนต์ เสร็จแล้วสำหรับแคชที่อยู่ในขอบเขตเวิร์กเกอร์
- เหตุการณ์สตรีมพาเรนต์ ACP
- เหตุการณ์รันไทม์ทราเจกทอรีเมื่อไม่ใช่อาร์ติแฟกต์ส่งออกที่ชัดเจน
ระยะที่ 3: แทนที่ API ของที่เก็บเซสชัน
เสร็จแล้วสำหรับรันไทม์ พื้นผิวที่เก็บเซสชันแบบไฟล์ไม่ได้เป็นสัญญารันไทม์ที่ใช้งานอยู่:
- รันไทม์ไม่เรียก
loadSessionStore(storePath)อีกต่อไป และไม่ถือว่าstorePathเป็นตัวระบุเซสชัน - การดำเนินการกับแถวของรันไทม์คือ
getSessionEntry,upsertSessionEntry,patchSessionEntry,deleteSessionEntryและlistSessionEntries - ตัวช่วยเขียนทั้งสโตร์ใหม่ ตัวเขียนไฟล์ การทดสอบคิว การตัด alias และพารามิเตอร์การลบคีย์เดิมถูกนำออกจากรันไทม์แล้ว
- export ความเข้ากันได้ของแพ็กเกจรูทที่เลิกใช้แล้วยังคงปรับพาธ
sessions.jsonตามมาตรฐานเข้ากับ API แถว SQLite - การแยกวิเคราะห์
sessions.jsonเหลืออยู่เฉพาะในโค้ดการย้าย/นำเข้าของ doctor และการทดสอบ doctor - การอ่าน fallback ของวงจรชีวิตรันไทม์อ่านส่วนหัวทรานสคริปต์จาก SQLite ไม่ใช่บรรทัดแรกของ JSONL
ลบสิ่งใดก็ตามที่นำพารามิเตอร์ file-lock คำศัพท์เกี่ยวกับ pruning/truncation-as-file-maintenance ตัวตนแบบ store-path หรือการทดสอบที่มีข้อยืนยันเพียงอย่างเดียวคือการคงอยู่ของ JSON กลับเข้ามา
ระยะที่ 4: ย้ายทรานสคริปต์ สตรีม ACP ทราเจกทอรี และ VFS
ทำให้ทุกสตรีมข้อมูลเอเจนต์เป็นแบบฐานข้อมูลโดยตรง:
- การเขียน append ทรานสคริปต์ผ่านทรานแซกชัน SQLite เดียวที่รับประกันส่วนหัวเซสชัน ตรวจสอบ idempotency ของข้อความ เลือก tail ของพาเรนต์ แทรกลงใน
transcript_eventsและบันทึกเมตาดาต้าตัวตนที่ค้นหาได้ในtranscript_event_identitiesเสร็จแล้วสำหรับการ append ข้อความทรานสคริปต์โดยตรงและการ append ของTranscriptSessionManagerที่คงอยู่ตามปกติ การดำเนินการ branch ที่ชัดเจนยังคงใช้การเลือกพาเรนต์ที่ชัดเจนของตน และยังเขียนแถว SQLite โดยไม่อนุมานตัวระบุตำแหน่งไฟล์ใดๆ - บันทึกสตรีมพาเรนต์ ACP กลายเป็นแถว ไม่ใช่ไฟล์
.acp-stream.jsonlเสร็จแล้ว - การตั้งค่า spawn ของ ACP ไม่คงพาธ JSONL ของทรานสคริปต์อีกต่อไป เสร็จแล้ว
- การจับทราเจกทอรีของรันไทม์เขียนแถวเหตุการณ์/อาร์ติแฟกต์โดยตรง คำสั่ง support/export ที่ชัดเจนยังคงสร้างอาร์ติแฟกต์ JSONL ของ support-bundle เป็นรูปแบบส่งออกได้ แต่การส่งออกเซสชันจะไม่สร้าง JSONL ของเซสชันขึ้นใหม่ เสร็จแล้ว
- เวิร์กสเปซบนดิสก์ยังคงอยู่บนดิสก์เมื่อกำหนดค่าเป็นโหมดดิสก์
- VFS scratch และโหมดเวิร์กสเปซ VFS-only แบบทดลองใช้ DB ของเอเจนต์
การย้ายจะนำเข้าไฟล์ JSONL เก่าเพียงครั้งเดียว บันทึกจำนวน/แฮชใน
migration_runs และลบไฟล์ที่นำเข้าแล้วหลังจากตรวจสอบความสมบูรณ์
ระยะที่ 5: สำรองข้อมูล กู้คืน Vacuum และตรวจสอบ
การสำรองข้อมูลยังคงเป็นไฟล์ archive เดียว:
- checkpoint ฐานข้อมูล global และฐานข้อมูลเอเจนต์ทุกตัว
- snapshot แต่ละ DB ด้วย semantics การสำรองข้อมูลของ SQLite หรือ
VACUUM INTO - archive สแนปชอต DB ขนาดกะทัดรัด config ข้อมูลประจำตัวภายนอก และการส่งออกเวิร์กสเปซที่ร้องขอ
- ละเว้นไฟล์ live ดิบ
*.sqlite-walและ*.sqlite-shm - ตรวจสอบโดยเปิดสแนปชอต DB ทุกตัวและรัน
PRAGMA integrity_checkopenclaw backup createทำการตรวจสอบ archive นี้โดยค่าเริ่มต้น;--no-verifyข้ามเฉพาะ pass หลังเขียน archive ไม่ใช่การตรวจสอบความสมบูรณ์ตอนสร้างสแนปชอต - การกู้คืนคัดลอกสแนปชอตกลับไปยังพาธเป้าหมาย branch นี้รีเซ็ตเลย์เอาต์ SQLite ที่ยังไม่ shipped เป็น
user_version = 1; การเปลี่ยน schema ที่ shipped ในอนาคตสามารถเพิ่ม migration ที่ชัดเจนเมื่อจำเป็น
ระยะที่ 6: รันไทม์ของเวิร์กเกอร์
คงโหมดเวิร์กเกอร์ไว้เป็นแบบทดลองขณะที่การแยกฐานข้อมูลกำลังลงตัว:
- เวิร์กเกอร์ได้รับ agent id, run id, โหมด filesystem และตัวตนของ registry DB
- เวิร์กเกอร์แต่ละตัวเปิดการเชื่อมต่อ SQLite ของตนเอง
- พาเรนต์ยังคงถืออำนาจการส่งผ่านช่องทาง การอนุมัติ config และการยกเลิก
- เริ่มด้วยเวิร์กเกอร์หนึ่งตัวต่อการรันที่ใช้งานอยู่ เพิ่ม pooling เฉพาะหลังจากวงจรชีวิตและความเป็นเจ้าของการเชื่อมต่อ DB เสถียรแล้ว
ระยะที่ 7: ลบโลกเก่า
เสร็จแล้วสำหรับการจัดการเซสชันรันไทม์ โลกเก่าอนุญาตเฉพาะในฐานะอินพุต doctor ที่ชัดเจนหรือเอาต์พุต support/export เท่านั้น:
- ไม่มีการเขียน
sessions.json, transcript JSONL, sandbox registry JSON, task sidecar SQLite หรือ plugin-state sidecar SQLite ในรันไทม์ - ไม่มีการ pruning ไฟล์ JSON/session, การตัดทอน transcript ไฟล์, session file locks หรือการทดสอบเซสชันรูปแบบ lock
- ไม่มี export ความเข้ากันได้ของรันไทม์ที่มีวัตถุประสงค์เพื่อทำให้ไฟล์เซสชันเก่าเป็นปัจจุบัน
- export ฝ่าย support ที่ชัดเจนยังคงเป็นรูปแบบ archive/materialization ที่ผู้ใช้ร้องขอ และต้องไม่ป้อนชื่อไฟล์กลับเข้าไปเป็นตัวตนของรันไทม์
การสำรองข้อมูลและการกู้คืน
การสำรองข้อมูลควรเป็นไฟล์ archive เดียว แต่การจับฐานข้อมูลควรเป็นแบบ SQLite-native:
- หยุดกิจกรรมเขียนที่รันยาวหรือเข้าสู่ backup barrier สั้นๆ
- สำหรับฐานข้อมูล global และฐานข้อมูลเอเจนต์ทุกตัว ให้รัน checkpoint
- snapshot ฐานข้อมูลแต่ละตัวโดยใช้ semantics การสำรองข้อมูลของ SQLite หรือ
VACUUM INTOไปยังไดเรกทอรีสำรองข้อมูลชั่วคราว - archive สแนปชอตฐานข้อมูลที่ compact แล้ว ไฟล์ config ไดเรกทอรีข้อมูลประจำตัว เวิร์กสเปซที่เลือก และ manifest
- ตรวจสอบ archive โดยเปิดสแนปชอต SQLite ทุกตัวที่รวมอยู่และรัน
PRAGMA integrity_checkopenclaw backup createทำสิ่งนี้โดยค่าเริ่มต้น;--no-verifyมีไว้เฉพาะสำหรับการข้าม pass หลังเขียน archive โดยตั้งใจ
อย่าพึ่งสำเนา live ดิบของ *.sqlite, *.sqlite-wal และ *.sqlite-shm เป็นรูปแบบสำรองข้อมูลหลัก manifest ของ archive ควรบันทึกบทบาทฐานข้อมูล, agent id, เวอร์ชัน schema, พาธต้นทาง, พาธสแนปชอต, ขนาดไบต์ และสถานะความสมบูรณ์
การกู้คืนควรสร้างไฟล์ฐานข้อมูล global และไฟล์ฐานข้อมูลเอเจนต์ใหม่จากสแนปชอตใน archive เนื่องจากเลย์เอาต์ SQLite ยังไม่ได้ shipped refactor นี้จึงคงไว้เฉพาะ schema เวอร์ชัน 1 พร้อมการนำเข้าไฟล์ไปยังฐานข้อมูลของ doctor คำสั่ง restore จะตรวจสอบ archive ก่อน จากนั้นแทนที่ asset แต่ละรายการใน manifest จาก payload ที่แตกไฟล์และตรวจสอบแล้ว
แผน Refactor รันไทม์
-
เพิ่ม API registry ฐานข้อมูล
- resolve พาธ DB global และ DB ต่อเอเจนต์
- คง schema ที่ยังไม่ shipped ไว้ที่
user_version = 1; อย่าเพิ่มโค้ด schema migration runner จนกว่า schema ที่ shipped จะต้องใช้ - เพิ่มตัวช่วย close/checkpoint/integrity ที่ใช้โดยการทดสอบ การสำรองข้อมูล และ doctor
-
รวม sidecar SQLite stores
- ย้ายตาราง plugin state เข้าไปในฐานข้อมูล global เสร็จแล้วสำหรับการเขียนรันไทม์; ตัวนำเข้า sidecar legacy ที่ยังไม่ shipped ถูกลบแล้ว
- ย้ายตาราง task registry เข้าไปในฐานข้อมูล global เสร็จแล้วสำหรับการเขียนรันไทม์; ตัวนำเข้า sidecar legacy ที่ยังไม่ shipped ถูกลบแล้ว
- ย้ายตาราง Task Flow เข้าไปในฐานข้อมูล global เสร็จแล้วสำหรับการเขียนรันไทม์; ตัวนำเข้า sidecar legacy ที่ยังไม่ shipped ถูกลบแล้ว
- ย้ายตาราง builtin memory-search เข้าไปในฐานข้อมูลเอเจนต์แต่ละตัว เสร็จแล้ว;
memorySearch.store.pathแบบกำหนดเองที่ชัดเจนถูกลบโดยการย้าย config ของ doctor แล้ว การ reindex เต็มรันในที่เดิมกับตาราง memory เท่านั้น; พาธ swap ทั้งไฟล์เก่าและตัวช่วย swap ดัชนี sidecar ถูกลบแล้ว - ลบตัวเปิดฐานข้อมูลซ้ำ การตั้งค่า WAL ตัวช่วย permission และพาธ close จาก subsystem เหล่านั้น
-
ย้ายตารางที่เอเจนต์เป็นเจ้าของเข้าไปในฐานข้อมูลต่อเอเจนต์
- สร้าง DB เอเจนต์เมื่อต้องการผ่าน registry ฐานข้อมูล global เสร็จแล้ว
- ย้าย session entries ของรันไทม์, transcript events, แถว VFS และ tool artifacts ไปยัง DB เอเจนต์ เสร็จแล้ว
- อย่า migrate session entries, transcript events, แถว VFS หรือ tool artifacts ของ shared-DB เฉพาะ branch; เลย์เอาต์นั้นไม่เคย shipped คงไว้เฉพาะการนำเข้า legacy file-to-database ใน doctor
-
แทนที่ API ของที่เก็บเซสชัน
- ลบ
storePathออกจากการเป็นตัวตนรันไทม์ เสร็จแล้วสำหรับรันไทม์และถูกป้องกันโดยcheck:database-first-legacy-stores: metadata เซสชัน, route updates, command persistence, CLI session cleanup, Feishu reasoning previews, transcript-state persistence, subagent depth, auth profile session overrides, parent-fork logic และการตรวจสอบ QA-lab ตอนนี้ resolve ฐานข้อมูลจาก agent/session keys ตามมาตรฐาน การตอบกลับ session-list ของ Gateway/TUI/UI/macOS ตอนนี้ exposedatabasePathแทนpathแบบ legacy; พื้นผิว debug ของ macOS แสดงฐานข้อมูลต่อเอเจนต์เป็นสถานะอ่านอย่างเดียวแทนการเขียน configsession.store/status, การส่งออกทราเจกทอรีที่ขับเคลื่อนด้วยแชต และ CLI dependency proxies ไม่ propagate legacy store paths อีกต่อไป; transcript usage fallback อ่าน SQLite ด้วยตัวตน agent/session การทดสอบ runtime และ bridge ไม่ exposestorePathอีกต่อไป; อินพุต doctor/migration เป็นเจ้าของชื่อฟิลด์ legacy นั้น การโหลด combined-session ของ Gateway ไม่มี branch รันไทม์พิเศษสำหรับค่าsession.storeแบบ non-templated อีกต่อไป; โดย aggregate แถว SQLite ต่อเอเจนต์ lane doctor ของ legacy session-lock และตัวช่วย cleanup.jsonl.lockถูกลบแล้ว; ตอนนี้ SQLite เป็นขอบเขต concurrency ของเซสชัน call site รันไทม์แบบ hot ใช้ชื่อตัวช่วยเชิงแถว เช่นresolveSessionRowEntry; alias ความเข้ากันได้เก่าresolveSessionStoreEntryถูกลบออกจาก runtime และ plugin SDK exports แล้ว
- ลบ
- ใช้การดำเนินการแถว
{ agentId, sessionKey }เสร็จแล้ว:getSessionEntry,upsertSessionEntry,deleteSessionEntry,patchSessionEntryและlistSessionEntriesเป็น API แบบ SQLite-first ที่ไม่ต้องใช้พาธ session store สรุปสถานะ สถานะเอเจนต์ local, health และคำสั่ง listingopenclaw sessionsตอนนี้อ่านแถวต่อเอเจนต์โดยตรงและแสดงพาธฐานข้อมูล SQLite ต่อเอเจนต์แทนพาธsessions.json - แทนที่การ delete/insert ทั้งสโตร์ด้วย
upsertSessionEntry,deleteSessionEntry,listSessionEntriesและคำสั่ง cleanup SQL เสร็จแล้วสำหรับรันไทม์: hot paths ตอนนี้ใช้ row APIs และ row patches ที่ retry เมื่อ conflict; ตัวช่วย import/replace ทั้งสโตร์ที่เหลือถูกจำกัดไว้ที่โค้ด migration import และการทดสอบ backend SQLite- ลบ
store-writer.tsและ writer-queue tests เสร็จแล้ว - ลบการ pruning legacy-key ของรันไทม์และพารามิเตอร์ alias-delete จาก session row upserts/patches เสร็จแล้ว
- ลบ
- ลบพฤติกรรม JSON registry ของรันไทม์
- ทำให้การอ่านและเขียน sandbox registry เป็น SQLite-only เสร็จแล้ว
- นำเข้า JSON แบบ monolithic และ sharded เฉพาะจากขั้นตอน migration เสร็จแล้ว
- ลบ sharded registry locks และการเขียน JSON เสร็จแล้ว
- คงตาราง registry ที่ typed หนึ่งตารางไว้แทนการเก็บแถว registry เป็น JSON ทึบ generic หากรูปทรงยังคงเป็นสถานะปฏิบัติการบน hot-path เสร็จแล้ว
-
ลบการกลายพันธุ์เซสชันรูปแบบ file-lock
- เสร็จแล้วสำหรับการสร้าง lock ของรันไทม์และ API lock ของรันไทม์
- lane cleanup doctor
.jsonl.lockแบบ legacy แยกเดี่ยวถูกลบแล้ว session.writeLockเป็น config legacy ที่ doctor-migrated ไม่ใช่การตั้งค่ารันไทม์แบบ typed- ความสมบูรณ์ของ state ไม่มีพาธ pruning ไฟล์ transcript กำพร้าแยกต่างหากอีกต่อไป; การย้ายของ doctor นำเข้า/ลบแหล่ง JSONL legacy ในที่เดียว
- การประสานงาน singleton ของ Gateway ใช้แถว SQLite
state_leasesแบบ typed ใต้gateway_locksและไม่ expose seam ไดเรกทอรี file-lock อีกต่อไป - การคงอยู่ dedupe ของ plugin SDK แบบ generic ไม่ใช้ file locks หรือไฟล์ JSON อีกต่อไป; เขียนแถว plugin-state ของ SQLite ที่ใช้ร่วมกัน เสร็จแล้ว
- การประสานงาน QMD embed ใช้ state lease ของ SQLite แทน
qmd/embed.lockเสร็จแล้ว
-
ทำให้เวิร์กเกอร์รู้จักฐานข้อมูล
- เวิร์กเกอร์เปิดการเชื่อมต่อ SQLite ของตนเอง
- พาเรนต์เป็นเจ้าของ delivery, channel callbacks และ config
- เวิร์กเกอร์ได้รับ agent id, run id, โหมด filesystem และตัวตนของ registry DB ไม่ใช่ live handles
vfs-onlyยังคงเป็นแบบทดลองและใช้ฐานข้อมูลเอเจนต์เป็นรูทของ storage- คงเวิร์กเกอร์หนึ่งตัวต่อการรันที่ใช้งานอยู่ก่อน Pooling รอได้จนกว่าอายุการเชื่อมต่อ DB และพฤติกรรมการยกเลิกจะเรียบง่ายขึ้น
-
การผสานรวมการสำรองข้อมูล.
- สอนให้การสำรองข้อมูล snapshot ฐานข้อมูลส่วนกลางและฐานข้อมูลของเอเจนต์ผ่านการสำรองข้อมูลของ SQLite หรือ
VACUUM INTOเสร็จแล้วสำหรับไฟล์*.sqliteที่ค้นพบใต้แอสเซ็ตสถานะ - เพิ่มการตรวจสอบการสำรองข้อมูลสำหรับความสมบูรณ์ของ SQLite และเวอร์ชัน schema เสร็จแล้วสำหรับ การสร้างข้อมูลสำรองและการตรวจสอบความสมบูรณ์ของ archive เริ่มต้น
- บันทึก metadata ของการรันสำรองข้อมูลใน SQLite เสร็จแล้วผ่านตาราง
backup_runsที่ใช้ร่วมกัน โดยมี path ของ archive, สถานะ และ manifest JSON - เพิ่มการกู้คืนจาก snapshot ของ archive ที่ผ่านการตรวจสอบแล้ว เสร็จแล้ว:
openclaw backup restoreตรวจสอบก่อนแตกไฟล์ ใช้ manifest ที่ normalize แล้วของ verifier รองรับ--dry-runและต้องใช้--yesก่อนแทนที่ path ต้นทางที่บันทึกไว้ - รวมการ export VFS/workspace เฉพาะเมื่อมีการร้องขอเท่านั้น; อย่า export internals ของ session เป็น JSON หรือ JSONL
- สอนให้การสำรองข้อมูล snapshot ฐานข้อมูลส่วนกลางและฐานข้อมูลของเอเจนต์ผ่านการสำรองข้อมูลของ SQLite หรือ
-
ลบการทดสอบและโค้ดที่ล้าสมัย เสร็จแล้วสำหรับพื้นผิว runtime session ที่ทราบ
-
ลบการทดสอบที่ assert การสร้าง
sessions.jsonหรือไฟล์ transcript JSONL โดย runtime เสร็จแล้วสำหรับ core session store, chat, เหตุการณ์ transcript ของ Gateway, preview, lifecycle, การอัปเดต command session-entry, การ reset/trace ของ auto-reply และ fixture ของ memory-core dreaming, การ route approval target, การซ่อมแซม session transcript, การซ่อมแซม security permission, การ export trajectory และการ export session ตอนนี้การทดสอบ transcript ของ Active Memory assert scope ของ SQLite และไม่มีการสร้างไฟล์ JSONL ชั่วคราวหรือที่ persist แล้ว regression เก่าของ heartbeat transcript-pruning ถูกลบแล้วเพราะ runtime ไม่ truncate transcript JSONL อีกต่อไป การทดสอบเครื่องมือ agent session-list ไม่ model pathsessions.jsonแบบ legacy เป็น shape ของการตอบกลับ Gateway อีกต่อไป; การทดสอบ app/UI/macOS ใช้databasePathตอนนี้การทดสอบ/statustranscript-usage seed row ของ SQLite transcript โดยตรง แทนการเขียนไฟล์ JSONL ตอนนี้การทดสอบ Gateway session lifecycle ใช้ helper สำหรับ seed SQLite transcript โดยตรง; shape fixture session-file แบบ single-line เก่าหายไปจาก coverage ของ reset และ deletesessions.deleteไม่ return ฟิลด์ยุคไฟล์archived: []อีกต่อไป; การลบ รายงานเฉพาะผลลัพธ์การ mutate row เท่านั้น ตัวเลือกdeleteTranscriptเก่า ก็หายไปด้วย: การลบ session จะลบ rootsessionsที่เป็น canonical และให้ SQLite cascade row ของ transcript, snapshot และ trajectory ที่ session เป็นเจ้าของ ดังนั้น caller จะไม่สามารถทิ้ง transcript orphan ไว้หรือพลาด branch cleanup ได้ ตอนนี้การทดสอบ context-engine trajectory capture อ่าน rowtrajectory_runtime_eventsจากฐานข้อมูลเอเจนต์ที่แยกไว้ แทนการอ่านsession.trajectory.jsonlตอนนี้สคริปต์ seed ของ Docker MCP channel seed row ของ SQLite โดยตรง การเขียนsessions.jsonโดยตรงถูกจำกัดไว้เฉพาะ fixture ของ doctor Tool Search Gateway E2E อ่านหลักฐาน tool-call จาก row ของ SQLite transcript แทนการ scan ไฟล์agents/<agentId>/sessions/*.jsonlตอนนี้ host events และ row ชั่วคราวของ session-corpus ใน memory-core อยู่ใน plugin-state ของ SQLite ที่ใช้ร่วมกัน;events.jsonlและsession-corpus/*.txtเป็นเพียง input migration แบบ legacy ของ doctor เท่านั้น Row ที่ active ใช้ path เสมือนmemory/session-ingestion/ไม่ใช่.dreams/session-corpusโมดูลซ่อมแซม memory-core dreaming เก่าและการทดสอบ CLI/Gateway ของโมดูลนั้นถูกลบแล้ว เพราะ runtime ไม่ได้เป็นเจ้าของการซ่อมแซม file archive สำหรับ corpus นั้นอีกต่อไป การทดสอบ bridge/public-artifact ของ memory-core ไม่ surface.dreams/events.jsonlอีกต่อไป; การทดสอบเหล่านั้น ใช้ชื่อ artifact JSON เสมือนที่ backing ด้วย SQLite ตอนนี้เอกสารการทดสอบ Public SDK/Codex ระบุสถานะ session ของ SQLite แทนไฟล์ session และตัวอย่าง channel-turn ไม่ expose argumentstorePathอีกต่อไป ตอนนี้ state การ sync ของ Matrix ใช้ store plugin-state ของ SQLite โดยตรง สัญญา client/runtime ที่ active ส่งผ่าน root ของ account storage ไม่ใช่ pathbot-storage.jsonและ doctor importbot-storage.jsonแบบ legacy เข้า SQLite ก่อนลบ ต้นทาง ตอนนี้ scenario การ restart/destructive ของ QA Matrix mutate row sync ของ SQLite โดยตรง แทนการสร้างหรือลบไฟล์bot-storage.jsonปลอม และ substrate ของ E2EE ส่งผ่าน root ของ sync-store แทน pathsync-store.jsonปลอม การเลือก storage-root ของ Matrix ไม่ให้คะแนน root จากไฟล์ JSON sync/thread แบบ legacy อีกต่อไป; ใช้ root metadata ที่ durable พร้อม state crypto จริง test suite ของ runtime SQLite session backend ไม่ fabricatesessions.jsonอีกต่อไป; fixture ต้นทาง legacy ตอนนี้อยู่ในการทดสอบ doctor ที่ import fixture เหล่านั้น การทดสอบ Gateway session ไม่ expose helpercreateSessionStoreDirหรือ การตั้งค่า path session-store ชั่วคราวที่ไม่ได้ใช้อีกต่อไป; dir ของ fixture ชัดเจน และการตั้งค่า row โดยตรงใช้การตั้งชื่อ session-row ของ SQLite coverage parser ของ doctor-only JSON5 session-store ย้ายออกจากการทดสอบ infra และ ไปอยู่ในการทดสอบ migration ของ doctor ดังนั้น test suite ของ runtime จึงไม่ได้เป็นเจ้าของการ parse session-file แบบ legacy อีกต่อไป การทดสอบ runtime SSO/pending-upload ของ Microsoft Teams ไม่พก fixture sidecar JSON หรือ parser อีกต่อไป; การ parse token SSO แบบ legacy อยู่ในโมดูล migration ของ Plugin เท่านั้น การทดสอบ Telegram ไม่ seed path store/tmp/*.jsonปลอมอีกต่อไป; การทดสอบเหล่านั้น reset message cache ที่ backing ด้วย SQLite โดยตรง helper test-state ทั่วไปของ OpenClaw ไม่ expose writerauth-profiles.jsonแบบ legacy อีกต่อไป; การทดสอบ auth migration ของ doctor เป็นเจ้าของ fixture นั้นแบบ local การทดสอบ runtime สำหรับ pointer last-session ของ TUI, exec approvals, toggle ของ active-memory, การตรวจสอบ Matrix dedupe/startup, การ sync source ของ Memory Wiki, binding ของ current-conversation, onboarding auth และ secret import ของ Hermes ไม่ สร้างไฟล์ sidecar เก่าหรือ assert ว่า filename เก่าหายไปอีกต่อไป การทดสอบเหล่านั้น พิสูจน์พฤติกรรมผ่าน row ของ SQLite และ public store API; การทดสอบ doctor/migration เป็นที่เดียวที่ filename ต้นทาง legacy ควรอยู่ การทดสอบ runtime สำหรับการจับคู่ device/node, channel allowFrom, restart intents, restart handoff, entry ของ session delivery queue, config health, cache ของ iMessage, cron jobs, header ของ PI transcript, registry ของ subagent และ image attachment ที่จัดการแล้ว ก็ไม่สร้างไฟล์ JSON/JSONL ที่ปลดระวางแล้วเพียงเพื่อพิสูจน์ว่าไฟล์เหล่านั้นถูก ignored หรือ absent อีกต่อไป PI overflow recovery ไม่มี fallback การ rewrite/truncation ของ SessionManager อีกต่อไป: การ truncate tool-result และการ rewrite transcript ของ context-engine mutate row ของ SQLite transcript แล้ว refresh active prompt state จากฐานข้อมูล การ append message ของ SessionManager ที่ persist แล้ว delegate ไปยัง helper append transcript ของ SQLite แบบ atomic สำหรับการเลือก parent และ idempotency การ append entry metadata/custom ปกติก็เลือก parent ปัจจุบันภายใน SQLite ด้วย ดังนั้น instance ของ manager ที่ stale จะไม่ resurrect race ของ parent-chain ก่อน SQLite การ cleanup tail แบบ synthetic ของ PI สำหรับ mid-turn precheck และsessions_yieldตอนนี้ trim state ของ SQLite transcript โดยตรง; bridge tail-removal ของ SessionManager เก่า และการทดสอบของมันถูกลบแล้ว การจับ checkpoint ของ Compaction ก็ snapshot จาก SQLite เท่านั้น; caller ไม่ ส่ง SessionManager ที่ live เป็นแหล่ง transcript ทางเลือกอีกต่อไป -
เก็บการทดสอบที่ seed ไฟล์ legacy ไว้เฉพาะสำหรับ migration
-
หลักฐานแบบไฟล์ JSON ถูกแทนที่ด้วยหลักฐาน row ของ SQL สำหรับพื้นผิว runtime ที่ active
-
เพิ่ม static ban สำหรับ runtime writes ไปยัง path JSON ของ session/cache แบบ legacy เสร็จแล้วสำหรับ repo guard
- ทำให้รายงาน migration ตรวจสอบย้อนหลังได้
- บันทึกการรัน migration ใน SQLite พร้อม timestamp เริ่มต้น/สิ้นสุด, path ต้นทาง,
hash ต้นทาง, count, warning และ path สำรองข้อมูล
เสร็จแล้ว: ตอนนี้การทำงานของ legacy-state migration persist รายงาน
migration_runsพร้อม inventory ของ source path/table, SHA-256 ของไฟล์ต้นทาง, size, record count, warning และ path สำรองข้อมูล เสร็จแล้ว: การทำงานของ legacy-state migration ยัง persist rowmigration_sourcesสำหรับ audit ระดับ source และการตัดสินใจ skip/backfill ในอนาคต - ทำให้การ apply เป็น idempotent การรันซ้ำหลังจาก import บางส่วนควร skip source ที่ import แล้ว หรือ merge ด้วย stable key เสร็จแล้ว: session index, transcript, delivery queue, plugin state, task ledger และ row ของ SQLite global ที่ agent เป็นเจ้าของ import ผ่าน stable key หรือ semantics แบบ upsert/replace ดังนั้นการรันซ้ำจะ merge โดยไม่ duplicate row durable
- import ที่ล้มเหลวต้องเก็บไฟล์ต้นฉบับไว้ที่เดิม
เสร็จแล้ว: ตอนนี้ import transcript ที่ล้มเหลวทิ้ง source JSONL เดิมไว้ที่
path ที่ตรวจพบ และ
migration_sourcesบันทึก source เป็นwarningพร้อมremoved_source=0สำหรับการรัน doctor ครั้งถัดไป
- บันทึกการรัน migration ใน SQLite พร้อม timestamp เริ่มต้น/สิ้นสุด, path ต้นทาง,
hash ต้นทาง, count, warning และ path สำรองข้อมูล
เสร็จแล้ว: ตอนนี้การทำงานของ legacy-state migration persist รายงาน
กฎด้านประสิทธิภาพ
- หนึ่ง connection ต่อ thread/process ใช้ได้; อย่า share handle ข้าม worker
- ใช้ WAL,
foreign_keys=ON, busy timeout 30 วินาที และ transaction เขียนแบบBEGIN IMMEDIATEที่สั้น - ให้ helper ของ write transaction เป็น synchronous ต่อไป เว้นแต่/จนกว่า API transaction แบบ async จะเพิ่ม semantics ของ mutex/backpressure อย่างชัดเจน
- ให้การเขียน parent delivery เล็กและเป็น transactional
- หลีกเลี่ยงการ rewrite ทั้ง store; ใช้ upsert/delete ระดับ row
- เพิ่ม index สำหรับ path list-by-agent, list-by-session, updated-at, run id และ expiration ก่อนย้าย hot code
- เก็บ artifact, media และ vector ขนาดใหญ่เป็น BLOB หรือ row BLOB แบบ chunked ไม่ใช่ JSON แบบ base64 หรือ numeric-array
- ให้ entry plugin-state แบบ opaque มีขนาดเล็กและ scoped
- เพิ่ม cleanup ของ SQL สำหรับ TTL/expiration แทนการ prune filesystem เสร็จแล้วสำหรับ runtime store ที่ฐานข้อมูลเป็นเจ้าของ: media, plugin state, plugin blobs, persistent dedupe และ agent cache ทั้งหมดหมดอายุผ่าน row ของ SQLite cleanup ของ filesystem ที่เหลือจำกัดไว้เฉพาะ materialization ชั่วคราวหรือคำสั่งลบ ที่ชัดเจน
Static Ban
เพิ่ม repo check ที่ fail runtime writes ใหม่ไปยัง path state แบบ legacy:
sessions.json*.trajectory.jsonlยกเว้นเอาต์พุต support-bundle ที่ materialized แล้ว.acp-stream.jsonlacp/event-ledger.json- ไฟล์แคชรันไทม์
cache/*.json agents/<agentId>/agent/auth.jsonagents/<agentId>/agent/models.jsoncredentials/oauth.jsongithub-copilot.token.jsonopenrouter-models.jsonauth-profiles.jsonauth-state.jsonexec-approvals.jsonworkspace-state.json- Matrix
credentials*.jsonและrecovery-key.json cron/runs/*.jsonlcron/jobs.jsonjobs-state.jsondevice-pair-notify.jsondevices/pending.jsondevices/paired.jsondevices/bootstrap.jsonnodes/pending.jsonnodes/paired.jsonidentity/device.jsonidentity/device-auth.jsonpush/web-push-subscriptions.jsonpush/vapid-keys.jsonpush/apns-registrations.jsonprocess-leases.jsongateway-instance-idsession-toggles.json- Memory-core
.dreams/events.jsonl - Memory-core
.dreams/session-corpus/ - Memory-core
.dreams/daily-ingestion.json - Memory-core
.dreams/session-ingestion.json - Memory-core
.dreams/short-term-recall.json - Memory-core
.dreams/phase-signals.json - Memory-core
.dreams/short-term-promotion.lock - Skill Workshop
skill-workshop/<workspace>.json - Skill Workshop
skill-workshop/skill-workshop-review-*.json - Nostr
bus-state-*.json - Nostr
profile-state-*.json calls.jsonlknown-users.jsonref-index.jsonl- QQBot
session-*.json - BlueBubbles
bluebubbles/catchup/*.json - BlueBubbles
bluebubbles/inbound-dedupe/*.json - Telegram
update-offset-*.json - Telegram
sticker-cache.json - Telegram
*.telegram-messages.json - Telegram
*.telegram-sent-messages.json - Telegram
*.telegram-topic-names.json - Telegram
thread-bindings-*.json - iMessage
catchup/*.json - iMessage
reply-cache.jsonl - iMessage
sent-echoes.jsonl - Microsoft Teams
msteams-conversations.json - Microsoft Teams
msteams-polls.json - Microsoft Teams
msteams-sso-tokens.json - Microsoft Teams
*.learnings.json - Matrix
bot-storage.json - Matrix
sync-store.json - Matrix
thread-bindings.json - Matrix
inbound-dedupe.json - Matrix
startup-verification.json - Matrix
storage-meta.json - Matrix
crypto-idb-snapshot.json - Discord
model-picker-preferences.json - Discord
command-deploy-cache.json - ไฟล์ JSON shard ของรีจิสทรี sandbox
- ไฟล์ JSON bridge ของ native hook relay
/tmp plugin-state/state.sqlite- sidecar รันไทม์
openclaw-state.sqliteแบบเฉพาะกิจ tasks/runs.sqlitetasks/flows/registry.sqlitebindings/current-conversations.jsonrestart-sentinel.jsongateway-restart-intent.jsongateway-supervisor-restart-handoff.jsongateway.<hash>.lockqmd/embed.lockcommands.logconfig-health.jsonport-guard.jsonsettings/voicewake.jsonsettings/voicewake-routing.jsonplugin-binding-approvals.jsonplugins/installs.jsonaudit/file-transfer.jsonlaudit/crestodian.jsonlcrestodian/rescue-pending/*.jsonplugins/phone-control/armed.json- Memory Wiki
.openclaw-wiki/log.jsonl - Memory Wiki
.openclaw-wiki/state.json - Memory Wiki
.openclaw-wiki/locks/ - Memory Wiki
.openclaw-wiki/source-sync.json - Memory Wiki
.openclaw-wiki/import-runs/*.json - Memory Wiki
.openclaw-wiki/cache/agent-digest.json - Memory Wiki
.openclaw-wiki/cache/claims.jsonl - ClawHub
.clawhub/lock.json - ClawHub
.clawhub/origin.json - การตกแต่งโปรไฟล์เบราว์เซอร์
.openclaw-profile-decorated - ตัวเปิดเซสชันที่รองรับด้วยไฟล์
SessionManager.open(...) - facade การแสดงรายการ transcript ของ
SessionManager.listAll(...)และTranscriptSessionManager.listAll(...) - facade การ fork transcript ของ
SessionManager.forkFromSession(...)และTranscriptSessionManager.forkFromSession(...) - facade การแทนที่เซสชันที่เปลี่ยนแปลงได้ของ
SessionManager.newSession(...)และTranscriptSessionManager.newSession(...) - facade เซสชัน branch ของ
SessionManager.createBranchedSession(...)และTranscriptSessionManager.createBranchedSession(...)
ข้อห้ามควรอนุญาตให้การทดสอบสร้าง fixture แบบ legacy และอนุญาตให้โค้ด migration อ่าน/นำเข้า/ลบแหล่งไฟล์ legacy ได้ SQLite sidecar ที่ยังไม่ได้ ship ยังคงถูกห้าม และไม่ได้รับข้อยกเว้นให้ doctor นำเข้า
เกณฑ์เสร็จสิ้น
- การเขียนข้อมูลรันไทม์และแคชไปยังฐานข้อมูล SQLite ระดับ global หรือ agent
- รันไทม์ไม่เขียนดัชนีเซสชัน, transcript JSONL, JSON ของรีจิสทรี sandbox, task sidecar SQLite หรือ plugin-state sidecar SQLite อีกต่อไป ตัวนำเข้า task และ plugin-state sidecar SQLite ที่ยังไม่ได้ ship ถูกลบแล้ว
- การนำเข้าไฟล์ legacy ทำได้เฉพาะ doctor เท่านั้น
- Backup สร้าง archive เดียวที่มี snapshot SQLite แบบกระชับและหลักฐานความสมบูรณ์
- agent worker สามารถรันด้วย disk, VFS scratch หรือ storage แบบ VFS-only ทดลองได้
- ไฟล์ config และไฟล์ credential ที่ระบุชัดเจนยังคงเป็นไฟล์ควบคุมถาวรที่ไม่ใช่ฐานข้อมูลเพียงประเภทเดียวที่คาดไว้
- การตรวจสอบ repo ป้องกันการนำที่เก็บไฟล์รันไทม์ legacy กลับมาใช้อีกครั้ง