- หน้าแรก
- Documentation
- เซสชัน
- การดำเนินการกับเซสชัน: export, dump, share, fork, resume/continue
การดำเนินการกับเซสชัน: export, dump, share, fork, resume/continue
เอกสารนี้อธิบายพฤติกรรมที่ผู้ดำเนินการมองเห็นได้สำหรับการดำเนินการ export/share/fork/resume ของเซสชัน ตามที่ได้นำไปใช้งานในปัจจุบัน
ไฟล์การนำไปใช้งาน
หัวข้อที่มีชื่อว่า “ไฟล์การนำไปใช้งาน”../src/modes/controllers/command-controller.ts../src/session/agent-session.ts../src/session/session-manager.ts../src/export/html/index.ts../src/export/custom-share.ts../src/main.ts
เมทริกซ์การดำเนินการ
หัวข้อที่มีชื่อว่า “เมทริกซ์การดำเนินการ”| การดำเนินการ | เส้นทางเข้าใช้งาน | การเปลี่ยนแปลงเซสชัน | การสร้าง/สลับไฟล์เซสชัน | ผลลัพธ์ที่ได้ |
|---|---|---|---|---|
/dump | คำสั่ง slash แบบโต้ตอบ | ไม่มี | ไม่มี | ข้อความในคลิปบอร์ด |
/export [path] | คำสั่ง slash แบบโต้ตอบ | ไม่มี | ไม่มี | ไฟล์ HTML |
--export <session.jsonl> [outputPath] | เส้นทางเร็วเมื่อเริ่ม CLI | ไม่มีการเปลี่ยนแปลงเซสชันขณะทำงาน | ไม่มีเซสชันที่ใช้งานอยู่; อ่านไฟล์เป้าหมาย | ไฟล์ HTML |
/share | คำสั่ง slash แบบโต้ตอบ | ไม่มี | ไม่มี | HTML ชั่วคราว + URL แชร์/gist |
/fork | คำสั่ง slash แบบโต้ตอบ | มี (เอกลักษณ์เซสชันที่ใช้งานอยู่เปลี่ยนแปลง) | สร้างไฟล์เซสชันใหม่และสลับเซสชันปัจจุบันไปยังไฟล์นั้น (เฉพาะโหมดถาวร) | คัดลอกไดเรกทอรีอาร์ติแฟกต์ไปยังเนมสเปซเซสชันใหม่เมื่อมีอยู่ |
/resume | คำสั่ง slash แบบโต้ตอบ | มี (สถานะในหน่วยความจำที่ใช้งานอยู่ถูกแทนที่) | สลับไปยังไฟล์เซสชันที่มีอยู่ที่เลือก | ไม่มี |
--resume | เริ่ม CLI (ตัวเลือก) | มี หลังจากสร้างเซสชัน | เปิดไฟล์เซสชันที่มีอยู่ที่เลือก | ไม่มี |
--resume <id|path> | เริ่ม CLI | มี หลังจากสร้างเซสชัน | เปิดเซสชันที่มีอยู่; กรณีข้ามโปรเจกต์สามารถแยกสาขาไปยังโปรเจกต์ปัจจุบันได้ | ไม่มี |
--continue | เริ่ม CLI | มี หลังจากสร้างเซสชัน | เปิดเบรดครัมบ์เทอร์มินัลหรือเซสชันล่าสุด; สร้างอันใหม่หากไม่มี | ไม่มี |
การส่งออกและดัมพ์
หัวข้อที่มีชื่อว่า “การส่งออกและดัมพ์”/export [outputPath] (โต้ตอบ)
หัวข้อที่มีชื่อว่า “/export [outputPath] (โต้ตอบ)”ขั้นตอนการทำงาน:
InputControllerส่งต่อ/export...ไปยังCommandController.handleExportCommand- คำสั่งแยกตามช่องว่างและใช้เฉพาะอาร์กิวเมนต์แรกหลัง
/exportเป็นoutputPath AgentSession.exportToHtml()เรียกexportSessionToHtml(sessionManager, state, { outputPath, themeName })- เมื่อสำเร็จ UI จะแสดงเส้นทางและเปิดไฟล์ในเบราว์เซอร์
รายละเอียดพฤติกรรม:
- อาร์กิวเมนต์
--copy,clipboard, และcopyจะถูกปฏิเสธอย่างชัดเจนพร้อมคำเตือนให้ใช้/dumpแทน - การส่งออกฝังส่วนหัวเซสชัน/รายการ/ใบไม้ บวกกับ
systemPromptปัจจุบันและคำอธิบายเครื่องมือจากสถานะของเอเจนต์ - ไม่มีการเพิ่มรายการเซสชันในระหว่างการส่งออก
ข้อควรระวัง:
- การแยกวิเคราะห์อาร์กิวเมนต์อิงตามช่องว่าง (
text.split(/\s+/)) ดังนั้นเส้นทางที่มีเครื่องหมายอัญประกาศซึ่งมีช่องว่างจะไม่ถูกเก็บรักษาเป็นเส้นทางเดียวในเส้นทางคำสั่งนี้
--export <inputSessionFile> [outputPath] (CLI)
หัวข้อที่มีชื่อว่า “--export <inputSessionFile> [outputPath] (CLI)”ขั้นตอนการทำงานใน main.ts:
- จัดการแต่เนิ่น (ก่อนเริ่มต้นแบบโต้ตอบ/เซสชัน)
- เรียก
exportFromFile(inputPath, outputPath?) SessionManager.open(inputPath)โหลดรายการ จากนั้นสร้างและเขียน HTML- กระบวนการพิมพ์
Exported to: ...และออก
รายละเอียดพฤติกรรม:
- ไฟล์นำเข้าที่ไม่มีอยู่จะแสดงผลเป็น
File not found: <path> - เส้นทางนี้ไม่สร้าง
AgentSessionและไม่เปลี่ยนแปลงเซสชันที่กำลังทำงานอยู่
/dump (ส่งออกไปยังคลิปบอร์ดแบบโต้ตอบ)
หัวข้อที่มีชื่อว่า “/dump (ส่งออกไปยังคลิปบอร์ดแบบโต้ตอบ)”ขั้นตอนการทำงาน:
CommandController.handleDumpCommand()เรียกsession.formatSessionAsText()- หากได้สตริงว่าง จะรายงาน
No messages to dump yet. - มิฉะนั้นจะคัดลอกไปยังคลิปบอร์ดผ่าน
copyToClipboardของระบบ
เนื้อหาดัมพ์ประกอบด้วย:
- System prompt
- โมเดลที่ใช้งานอยู่/ระดับการคิด
- นิยามเครื่องมือ + พารามิเตอร์
- ข้อความผู้ใช้/ผู้ช่วย
- บล็อกการคิดและการเรียกใช้เครื่องมือ
- ผลลัพธ์เครื่องมือและบล็อกการทำงาน (ยกเว้นรายการ bash/python ที่มี
excludeFromContext) - รายการ custom/hook/file mention/branch summary/compaction summary
การดัมพ์ไม่ทำให้เกิดการเปลี่ยนแปลงความคงอยู่ของเซสชัน
การแชร์
หัวข้อที่มีชื่อว่า “การแชร์”/share ทำงานแบบโต้ตอบเท่านั้นและเริ่มต้นด้วยการส่งออกเซสชันปัจจุบันไปยังไฟล์ HTML ชั่วคราวเสมอ
ขั้นตอนที่ 1: การส่งออกชั่วคราว
หัวข้อที่มีชื่อว่า “ขั้นตอนที่ 1: การส่งออกชั่วคราว”- เส้นทางไฟล์ชั่วคราว:
${os.tmpdir()}/${Snowflake.next()}.html - ใช้
session.exportToHtml(tmpFile) - หากการส่งออกล้มเหลว (โดยเฉพาะเซสชันในหน่วยความจำ) การแชร์จะสิ้นสุดพร้อมข้อผิดพลาด
ขั้นตอนที่ 2: ตัวจัดการแชร์กำหนดเอง (หากมี)
หัวข้อที่มีชื่อว่า “ขั้นตอนที่ 2: ตัวจัดการแชร์กำหนดเอง (หากมี)”loadCustomShare() ตรวจสอบ ~/.xcsh/agent สำหรับไฟล์ที่พบก่อนในลำดับนี้:
share.tsshare.jsshare.mjs
ข้อกำหนด:
- โมดูลต้องส่งออกฟังก์ชัน
(htmlPath) => Promise<CustomShareResult | string | undefined>แบบ default
หากมีอยู่และใช้งานได้:
- UI เข้าสู่สถานะโหลด
Sharing... - การตีความผลลัพธ์ของตัวจัดการ:
- string => ถือเป็น URL แสดงและเปิด
- object => แสดง
urlและ/หรือmessage; เปิดurl undefined/falsy => แสดงข้อความทั่วไปSession shared
- ไฟล์ชั่วคราวจะถูกลบหลังจากเสร็จสิ้น
พฤติกรรม fallback ที่สำคัญ:
- หากมีตัวจัดการกำหนดเองแต่การโหลดล้มเหลว คำสั่งจะเกิดข้อผิดพลาดและส่งคืน
- หากตัวจัดการกำหนดเองทำงานและเกิดข้อผิดพลาด คำสั่งจะเกิดข้อผิดพลาดและส่งคืน
- ในทั้งสองกรณีที่ล้มเหลว จะไม่ ถอยกลับไปใช้ GitHub gist
- การถอยกลับไปใช้ gist เกิดขึ้นเฉพาะเมื่อไม่พบสคริปต์แชร์กำหนดเองเท่านั้น
ขั้นตอนที่ 3: การถอยกลับไปใช้ gist เริ่มต้น
หัวข้อที่มีชื่อว่า “ขั้นตอนที่ 3: การถอยกลับไปใช้ gist เริ่มต้น”เฉพาะเมื่อไม่พบตัวจัดการแชร์กำหนดเอง:
- ตรวจสอบ
gh auth status - แสดงโหลด
Creating gist... - รัน
gh gist create --public=false <tmpFile> - แยกวิเคราะห์ URL ของ gist ดึง gist id สร้าง preview URL
https://gistpreview.github.io/?<id> - แสดงทั้ง URL preview และ gist; เปิด preview
ความหมายของการยกเลิก/ยกเลิกการดำเนินการในการแชร์:
- โหลดมี hook
onAbortที่คืนค่า UI ของตัวแก้ไขและรายงานShare cancelled - คำสั่ง
gh gist createที่ทำงานอยู่ไม่ได้รับการส่งสัญญาณยกเลิกในเส้นทางโค้ดนี้; การยกเลิกอยู่ในระดับ UI และตรวจสอบหลังจากคำสั่งส่งคืน
การแยกสาขา (Fork)
หัวข้อที่มีชื่อว่า “การแยกสาขา (Fork)”/fork สร้างเซสชันใหม่จากเซสชันปัจจุบันและสลับเอกลักษณ์ของเซสชันที่ใช้งานอยู่
เงื่อนไขเบื้องต้นและการตรวจสอบเบื้องต้น
หัวข้อที่มีชื่อว่า “เงื่อนไขเบื้องต้นและการตรวจสอบเบื้องต้น”- หากเอเจนต์กำลังสตรีม
/forkจะถูกปฏิเสธพร้อมคำเตือน - ตัวบ่งชี้สถานะ/การโหลด UI จะถูกล้างก่อนดำเนินการ
ขั้นตอนระดับเซสชัน
หัวข้อที่มีชื่อว่า “ขั้นตอนระดับเซสชัน”AgentSession.fork():
- ส่ง
session_before_switchพร้อมreason: "fork"(สามารถยกเลิกได้) - ล้างการเขียนที่รอดำเนินการ
- เรียก
SessionManager.fork() - คัดลอกไดเรกทอรีอาร์ติแฟกต์จากเนมสเปซเซสชันเก่าไปยังเนมสเปซใหม่ (ทำได้ดีที่สุด; ความล้มเหลวในการคัดลอกที่ไม่ใช่ ENOENT จะถูกบันทึก ไม่ถือว่าร้ายแรง)
- อัปเดต
agent.sessionId - ส่ง
session_switchพร้อมreason: "fork"
พฤติกรรมของ SessionManager.fork():
- ต้องการโหมดถาวรและไฟล์เซสชันที่มีอยู่
- สร้าง session id ใหม่และเส้นทางไฟล์ JSONL ใหม่
- เขียนส่วนหัวใหม่ด้วย:
idใหม่- timestamp ใหม่
cwdไม่เปลี่ยนแปลงparentSessionตั้งค่าเป็น session id ก่อนหน้า
- เก็บรายการที่ไม่ใช่ส่วนหัวทั้งหมดไว้ในไฟล์ใหม่โดยไม่เปลี่ยนแปลง
พฤติกรรมแบบไม่ถาวร
หัวข้อที่มีชื่อว่า “พฤติกรรมแบบไม่ถาวร”- ตัวจัดการเซสชันในหน่วยความจำส่งคืน
undefinedจากfork() AgentSession.fork()ส่งคืนfalse- UI รายงาน
Fork failed (session not persisted or cancelled)
การกลับมาใช้งานต่อและการต่อเนื่อง
หัวข้อที่มีชื่อว่า “การกลับมาใช้งานต่อและการต่อเนื่อง”/resume แบบโต้ตอบ
หัวข้อที่มีชื่อว่า “/resume แบบโต้ตอบ”ขั้นตอนการทำงาน:
- เปิดตัวเลือกเซสชันที่เติมข้อมูลผ่าน
SessionManager.list(currentCwd, currentSessionDir) - เมื่อเลือกแล้ว
SelectorController.handleResumeSession(sessionPath)เรียกsession.switchSession(sessionPath) - UI ล้าง/สร้างแชทและ todos ใหม่ จากนั้นรายงาน
Resumed session
หมายเหตุ:
- ตัวเลือกนี้แสดงเซสชันเฉพาะในขอบเขตไดเรกทอรีเซสชันปัจจุบัน
- ไม่ใช้การค้นหาข้ามโปรเจกต์แบบทั่วโลก
CLI --resume
หัวข้อที่มีชื่อว่า “CLI --resume”--resume (ไม่มีค่า)
หัวข้อที่มีชื่อว่า “--resume (ไม่มีค่า)”main.tsแสดงรายการเซสชันสำหรับ cwd/sessionDir ปัจจุบันและเปิดตัวเลือก- เส้นทางที่เลือกจะเปิดด้วย
SessionManager.open(selectedPath)ก่อนสร้างเซสชัน
--resume <value>
หัวข้อที่มีชื่อว่า “--resume <value>”ลำดับการแก้ไขของ createSessionManager():
- หากค่าดูเหมือนเส้นทาง (
/,\, หรือ.jsonl) ให้เปิดโดยตรง - มิฉะนั้นให้ถือเป็นคำนำหน้า id:
- ค้นหาในขอบเขตปัจจุบัน (
SessionManager.list(cwd, sessionDir)) - หากไม่พบและไม่มี
sessionDirที่ชัดเจน ให้ค้นหาทั่วโลก (SessionManager.listAll())
- ค้นหาในขอบเขตปัจจุบัน (
พฤติกรรมเมื่อพบ id ข้ามโปรเจกต์:
- หาก cwd ของเซสชันที่พบแตกต่างจาก cwd ปัจจุบัน CLI จะถามว่า:
Session found in different project ... Fork into current directory? [y/N]
- หากตอบใช่:
SessionManager.forkFrom(match.path, cwd, sessionDir)สร้างไฟล์แยกสาขาใหม่ในเครื่อง - หากตอบไม่/ค่าเริ่มต้นแบบไม่ใช่ TTY: คำสั่งจะเกิดข้อผิดพลาด
CLI --continue
หัวข้อที่มีชื่อว่า “CLI --continue”SessionManager.continueRecent(cwd, sessionDir):
- แก้ไขไดเรกทอรีเซสชันสำหรับ cwd ปัจจุบัน
- อ่านเบรดครัมบ์ที่กำหนดขอบเขตเทอร์มินัลก่อน
- ถอยกลับไปใช้ไฟล์เซสชันที่แก้ไขล่าสุด
- เปิดเซสชันที่พบ; หากไม่มี ให้สร้างเซสชันใหม่
นี่คือพฤติกรรมเฉพาะเมื่อเริ่มต้น; ไม่มีคำสั่ง slash /continue แบบโต้ตอบ
วิธีที่การสลับเซสชันเปลี่ยนแปลงสถานะขณะทำงานจริง
หัวข้อที่มีชื่อว่า “วิธีที่การสลับเซสชันเปลี่ยนแปลงสถานะขณะทำงานจริง”AgentSession.switchSession(sessionPath) ดำเนินการเปลี่ยนผ่านขณะทำงานที่ใช้โดยการดำเนินการแบบ resume:
- ส่ง
session_before_switchพร้อมreason: "resume"และtargetSessionFile(สามารถยกเลิกได้) - ยกเลิกการสมัครรับเหตุการณ์ของเอเจนต์และยกเลิกงานที่กำลังดำเนินอยู่
- ล้างข้อความ steering/follow-up/next-turn ที่อยู่ในคิว
- ล้างการเขียนตัวจัดการเซสชันปัจจุบัน
sessionManager.setSessionFile(sessionPath)และอัปเดตagent.sessionId- สร้างบริบทเซสชันจากรายการที่โหลด
- ส่ง
session_switchพร้อมreason: "resume" - แทนที่ข้อความเอเจนต์จากบริบท
- คืนค่าโมเดล (หากมีในรีจิสทรีปัจจุบัน)
- คืนค่าหรือเริ่มต้นระดับการคิด
- เชื่อมต่อการสมัครรับเหตุการณ์เอเจนต์ใหม่
switchSession() เองไม่สร้างไฟล์เซสชันใหม่
การส่งเหตุการณ์และจุดยกเลิก
หัวข้อที่มีชื่อว่า “การส่งเหตุการณ์และจุดยกเลิก”hooks วงจรชีวิตของการสลับ/แยกสาขา
หัวข้อที่มีชื่อว่า “hooks วงจรชีวิตของการสลับ/แยกสาขา”สำหรับ newSession, fork, และ switchSession:
- เหตุการณ์ก่อน:
session_before_switch- เหตุผล:
new,fork,resume - สามารถยกเลิกได้โดยการส่งคืน
{ cancel: true }
- เหตุผล:
- เหตุการณ์หลัง:
session_switch- ชุดเหตุผลเดียวกัน
- รวม
previousSessionFile
ExtensionRunner.emit() ส่งคืนก่อนกำหนดเมื่อพบผลลัพธ์ก่อนเหตุการณ์ที่ยกเลิกแรก
พฤติกรรม onSession ของเครื่องมือกำหนดเอง
หัวข้อที่มีชื่อว่า “พฤติกรรม onSession ของเครื่องมือกำหนดเอง”SDK เชื่อมต่อเหตุการณ์เซสชันส่วนขยายกับ callbacks onSession ของเครื่องมือกำหนดเอง:
session_switch->onSession({ reason: "switch", previousSessionFile })session_branch->reason: "branch"session_start->reason: "start"session_tree->reason: "tree"session_shutdown->reason: "shutdown"
callbacks เหล่านี้มีไว้สำหรับการสังเกตเท่านั้น ไม่สามารถยกเลิกการสลับ/แยกสาขาได้
พื้นผิวการยกเลิกอื่น ๆ ที่เกี่ยวข้องกับเอกสารนี้
หัวข้อที่มีชื่อว่า “พื้นผิวการยกเลิกอื่น ๆ ที่เกี่ยวข้องกับเอกสารนี้”/forkถูกบล็อกขณะสตรีม (ผู้ใช้ต้องรอ/ยกเลิกการตอบสนองปัจจุบันก่อน)- ตัวเลือก
/resumeสามารถยกเลิกได้โดยผู้ใช้ปิดตัวเลือก --resume <id>ข้ามโปรเจกต์สามารถยกเลิกได้โดยการปฏิเสธพรอมต์การแยกสาขา/shareมีเส้นทางยกเลิก UI (Share cancelled) สำหรับขั้นตอน gist; ไม่เชื่อมต่อ semantics การฆิลกระบวนการสำหรับgh gist createในเส้นทางโค้ดนี้
พฤติกรรมเซสชันแบบไม่ถาวร (ในหน่วยความจำ)
หัวข้อที่มีชื่อว่า “พฤติกรรมเซสชันแบบไม่ถาวร (ในหน่วยความจำ)”เมื่อตัวจัดการเซสชันสร้างด้วย SessionManager.inMemory() (--no-session):
- เส้นทางไฟล์เซสชันไม่มีอยู่
/exportและ/shareล้มเหลวพร้อมข้อความCannot export in-memory session to HTML(ส่งต่อไปยัง UI ข้อผิดพลาดคำสั่ง)/forkล้มเหลวเพราะSessionManager.fork()ต้องการความคงอยู่/dumpยังคงใช้งานได้เพราะทำการ serialize สถานะเอเจนต์ในหน่วยความจำ- semantics ของ resume/continue ใน CLI จะถูกข้ามหากตั้งค่า
--no-sessionเพราะการสร้างตัวจัดการส่งคืนแบบในหน่วยความจำทันที
ข้อควรระวังที่ทราบในการนำไปใช้งาน (ตามโค้ดปัจจุบัน)
หัวข้อที่มีชื่อว่า “ข้อควรระวังที่ทราบในการนำไปใช้งาน (ตามโค้ดปัจจุบัน)”SelectorController.handleResumeSession()ไม่ตรวจสอบผลลัพธ์ boolean จากsession.switchSession(...); การสลับที่ถูกยกเลิกโดย hook ยังคงดำเนินผ่านเส้นทาง repaint/status “Resumed session” ของ UI ได้- ความล้มเหลวของ custom-share ใน
/shareจะไม่ลดระดับลงไปใช้ gist fallback เริ่มต้น; แต่จะสิ้นสุดคำสั่งพร้อมข้อผิดพลาด - การแยกวิเคราะห์อาร์กิวเมนต์ของ
/exportเป็นแบบง่ายและไม่เก็บรักษาเส้นทางที่มีเครื่องหมายอัญประกาศซึ่งมีช่องว่าง