- الرئيسية
- Documentation
- الجلسات
- تخزين الجلسة ونموذج الإدخالات
تخزين الجلسة ونموذج الإدخالات
هذا المستند هو المرجع الأساسي لكيفية تمثيل جلسات وكيل البرمجة، وحفظها، وترحيلها، وإعادة بنائها أثناء التشغيل.
النطاق
Section titled “النطاق”يغطي:
- تنسيق JSONL للجلسة وإدارة الإصدارات
- تصنيف الإدخالات ودلالات الشجرة (
id/parentId+ مؤشر الورقة) - سلوك الترحيل/التوافق عند تحميل ملفات قديمة أو تالفة
- إعادة بناء السياق (
buildSessionContext) - ضمانات الحفظ، سلوك الفشل، الاقتطاع/تخزين البيانات الكبيرة خارجياً
- تجريدات التخزين (
FileSessionStorage،MemorySessionStorage) والأدوات المساعدة ذات الصلة
لا يغطي سلوك عرض واجهة /tree بخلاف الدلالات التي تؤثر على بيانات الجلسة.
ملفات التنفيذ
Section titled “ملفات التنفيذ”src/session/session-manager.tssrc/session/messages.tssrc/session/session-storage.tssrc/session/history-storage.tssrc/session/blob-store.ts
التخطيط على القرص
Section titled “التخطيط على القرص”الموقع الافتراضي لملف الجلسة:
~/.xcsh/agent/sessions/--<cwd-encoded>--/<timestamp>_<sessionId>.jsonlيُشتق <cwd-encoded> من دليل العمل عن طريق إزالة الشرطة المائلة الأولى واستبدال / و\\ و: بـ -.
موقع مخزن البيانات الكبيرة:
~/.xcsh/agent/blobs/<sha256>تُكتب ملفات مسار التنقل للطرفية تحت:
~/.xcsh/agent/terminal-sessions/<terminal-id>يتكون محتوى مسار التنقل من سطرين: دليل العمل الأصلي، ثم مسار ملف الجلسة. تفضل continueRecent() هذا المؤشر المحدد بنطاق الطرفية قبل البحث عن أحدث وقت تعديل.
تنسيق الملف
Section titled “تنسيق الملف”ملفات الجلسة بتنسيق JSONL: كائن JSON واحد لكل سطر.
- السطر الأول هو دائماً رأس الجلسة (
type: "session"). - الأسطر المتبقية هي قيم
SessionEntry. - الإدخالات تعمل بنمط الإلحاق فقط أثناء التشغيل؛ التنقل بين الفروع يحرك مؤشراً (
leafId) بدلاً من تعديل الإدخالات الموجودة.
الرأس (SessionHeader)
Section titled “الرأس (SessionHeader)”{ "type": "session", "version": 3, "id": "1f9d2a6b9c0d1234", "timestamp": "2026-02-16T10:20:30.000Z", "cwd": "/work/pi", "title": "optional session title", "parentSession": "optional lineage marker"}ملاحظات:
versionاختياري في ملفات v1؛ غيابه يعني v1.parentSessionهو سلسلة نصية معتمة للتسلسل النسبي. الكود الحالي يكتب إما معرف جلسة أو مسار جلسة حسب التدفق (fork،forkFrom،createBranchedSession، أوnewSession({ parentSession })الصريح). تعامل معه كبيانات وصفية، وليس مفتاحاً أجنبياً مُحدد النوع.
قاعدة الإدخال (SessionEntryBase)
Section titled “قاعدة الإدخال (SessionEntryBase)”جميع الإدخالات غير الرأسية تتضمن:
{ "type": "...", "id": "8-char-id", "parentId": "previous-or-branch-parent", "timestamp": "2026-02-16T10:20:30.000Z"}يمكن أن يكون parentId بقيمة null للإدخال الجذري (أول إلحاق، أو بعد resetLeaf()).
تصنيف الإدخالات
Section titled “تصنيف الإدخالات”SessionEntry هو اتحاد من:
messagethinking_level_changemodel_changecompactionbranch_summarycustomcustom_messagelabelttsr_injectionsession_initmode_change
message
Section titled “message”يخزن AgentMessage مباشرة.
{ "type": "message", "id": "a1b2c3d4", "parentId": null, "timestamp": "2026-02-16T10:21:00.000Z", "message": { "role": "assistant", "provider": "anthropic", "model": "claude-sonnet-4-5", "content": [{ "type": "text", "text": "Done." }], "usage": { "input": 100, "output": 20, "cacheRead": 0, "cacheWrite": 0, "cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0, "total": 0 } }, "timestamp": 1760000000000 }}model_change
Section titled “model_change”{ "type": "model_change", "id": "b1c2d3e4", "parentId": "a1b2c3d4", "timestamp": "2026-02-16T10:21:30.000Z", "model": "openai/gpt-4o", "role": "default"}role اختياري؛ غيابه يُعامل كـ default في إعادة بناء السياق.
thinking_level_change
Section titled “thinking_level_change”{ "type": "thinking_level_change", "id": "c1d2e3f4", "parentId": "b1c2d3e4", "timestamp": "2026-02-16T10:22:00.000Z", "thinkingLevel": "high"}compaction
Section titled “compaction”{ "type": "compaction", "id": "d1e2f3a4", "parentId": "c1d2e3f4", "timestamp": "2026-02-16T10:23:00.000Z", "summary": "Conversation summary", "shortSummary": "Short recap", "firstKeptEntryId": "a1b2c3d4", "tokensBefore": 42000, "details": { "readFiles": ["src/a.ts"] }, "preserveData": { "hookState": true }, "fromExtension": false}branch_summary
Section titled “branch_summary”{ "type": "branch_summary", "id": "e1f2a3b4", "parentId": "a1b2c3d4", "timestamp": "2026-02-16T10:24:00.000Z", "fromId": "a1b2c3d4", "summary": "Summary of abandoned path", "details": { "note": "optional" }, "fromExtension": true}إذا كان التفرع من الجذر (branchFromId === null)، فإن fromId تكون السلسلة الحرفية "root".
custom
Section titled “custom”حفظ حالة الإضافات؛ يتم تجاهله بواسطة buildSessionContext.
{ "type": "custom", "id": "f1a2b3c4", "parentId": "e1f2a3b4", "timestamp": "2026-02-16T10:25:00.000Z", "customType": "my-extension", "data": { "state": 1 }}custom_message
Section titled “custom_message”رسالة مقدمة من الإضافة تشارك في سياق نموذج اللغة الكبير.
{ "type": "custom_message", "id": "a2b3c4d5", "parentId": "f1a2b3c4", "timestamp": "2026-02-16T10:26:00.000Z", "customType": "my-extension", "content": "Injected context", "display": true, "details": { "debug": false }}{ "type": "label", "id": "b2c3d4e5", "parentId": "a2b3c4d5", "timestamp": "2026-02-16T10:27:00.000Z", "targetId": "a1b2c3d4", "label": "checkpoint"}label: undefined يمسح التسمية لـ targetId.
ttsr_injection
Section titled “ttsr_injection”{ "type": "ttsr_injection", "id": "c2d3e4f5", "parentId": "b2c3d4e5", "timestamp": "2026-02-16T10:28:00.000Z", "injectedRules": ["ruleA", "ruleB"]}session_init
Section titled “session_init”{ "type": "session_init", "id": "d2e3f4a5", "parentId": "c2d3e4f5", "timestamp": "2026-02-16T10:29:00.000Z", "systemPrompt": "...", "task": "...", "tools": ["read", "edit"], "outputSchema": { "type": "object" }}mode_change
Section titled “mode_change”{ "type": "mode_change", "id": "e2f3a4b5", "parentId": "d2e3f4a5", "timestamp": "2026-02-16T10:30:00.000Z", "mode": "plan", "data": { "planFile": "/tmp/plan.md" }}إدارة الإصدارات والترحيل
Section titled “إدارة الإصدارات والترحيل”إصدار الجلسة الحالي: 3.
v1 -> v2
Section titled “v1 -> v2”يُطبق عندما يكون version في الرأس مفقوداً أو < 2:
- يضيف
idوparentIdلكل إدخال غير رأسي. - يعيد بناء سلسلة أصل خطية باستخدام ترتيب الملف.
- يرحل حقل الضغط
firstKeptEntryIndex->firstKeptEntryIdعند وجوده. - يضبط
version = 2في الرأس.
v2 -> v3
Section titled “v2 -> v3”يُطبق عندما يكون version < 3 في الرأس:
- لإدخالات
message: يعيد كتابةmessage.role === "hookMessage"القديم إلى"custom". - يضبط
version = 3في الرأس.
مُحفز الترحيل والحفظ
Section titled “مُحفز الترحيل والحفظ”- تعمل عمليات الترحيل أثناء تحميل الجلسة (
setSessionFile). - إذا تم تشغيل أي ترحيل، تتم إعادة كتابة الملف بالكامل على القرص فوراً.
- يقوم الترحيل بتعديل الإدخالات في الذاكرة أولاً، ثم يحفظ JSONL المعاد كتابته.
سلوك التحميل والتوافق
Section titled “سلوك التحميل والتوافق”سلوك loadEntriesFromFile(path):
- ملف مفقود (
ENOENT) -> يعيد[]. - الأسطر غير القابلة للتحليل يتم معالجتها بواسطة محلل JSONL المتساهل (
parseJsonlLenient). - إذا لم يكن أول إدخال محلل رأس جلسة صالح (
type !== "session"أوidنصي مفقود) -> يعيد[].
سلوك SessionManager.setSessionFile():
[]من المحمل تُعامل كجلسة فارغة/غير موجودة ويتم استبدالها بملف جلسة مُهيأ جديد في ذلك المسار.- الملفات الصالحة تُحمل، وتُرحل إذا لزم الأمر، وتُحل مراجع البيانات الكبيرة، ثم تُفهرس.
دلالات الشجرة والورقة
Section titled “دلالات الشجرة والورقة”النموذج الأساسي هو شجرة إلحاق فقط + مؤشر ورقة قابل للتغيير:
- كل طريقة إلحاق تنشئ إدخالاً جديداً واحداً بالضبط يكون
parentIdالخاص به هوleafIdالحالي. - يصبح الإدخال الجديد هو
leafIdالجديد. branch(entryId)يحركleafIdفقط؛ الإدخالات الموجودة تبقى دون تغيير.resetLeaf()يضبطleafId = null؛ الإلحاق التالي ينشئ إدخالاً جذرياً جديداً (parentId: null).branchWithSummary()يضبط الورقة على هدف التفرع ويلحق إدخالbranch_summary.
getEntries() يعيد جميع الإدخالات غير الرأسية بترتيب الإدراج. لا تُحذف الإدخالات الموجودة في التشغيل العادي؛ إعادة الكتابة تحافظ على التاريخ المنطقي مع تحديث التمثيل (الترحيلات، النقل، مساعدات إعادة الكتابة المستهدفة).
إعادة بناء السياق (buildSessionContext)
Section titled “إعادة بناء السياق (buildSessionContext)”buildSessionContext(entries, leafId, byId?) يحدد ما يُرسل إلى النموذج.
الخوارزمية:
- تحديد الورقة:
leafId === null-> يعيد سياقاً فارغاً.leafIdصريح -> يستخدم ذلك الإدخال إن وُجد.- وإلا يرجع للإدخال الأخير.
- التنقل في سلسلة
parentIdمن الورقة إلى الجذر ثم عكسها إلى مسار من الجذر إلى الورقة. - اشتقاق حالة التشغيل عبر المسار:
thinkingLevelمن أحدثthinking_level_change(الافتراضي"off")- خريطة النماذج من إدخالات
model_change(role ?? "default") models.defaultالاحتياطي من مزود/نموذج رسالة المساعد إذا لم يوجد تغيير نموذج صريحinjectedTtsrRulesمكررة الإزالة من جميع إدخالاتttsr_injection- الوضع/بيانات الوضع من أحدث
mode_change(الوضع الافتراضي"none")
- بناء قائمة الرسائل:
- إدخالات
messageتمر كما هي - إدخالات
custom_messageتصبح رسائلcustomمن نوع AgentMessages عبرcreateCustomMessage - إدخالات
branch_summaryتصبح رسائلbranchSummaryمن نوع AgentMessages عبرcreateBranchSummaryMessage - إذا وُجد
compactionعلى المسار:- يُصدر ملخص الضغط أولاً (
createCompactionSummaryMessage) - يُصدر إدخالات المسار بدءاً من
firstKeptEntryIdحتى حدود الضغط - يُصدر الإدخالات بعد حدود الضغط
- يُصدر ملخص الضغط أولاً (
- إدخالات
إدخالات custom وsession_init لا تحقن سياق النموذج مباشرة.
ضمانات الحفظ ونموذج الفشل
Section titled “ضمانات الحفظ ونموذج الفشل”الحفظ مقابل الذاكرة
Section titled “الحفظ مقابل الذاكرة”SessionManager.create/open/continueRecent/forkFrom-> وضع مستمر (persist = true).SessionManager.inMemory-> وضع غير مستمر (persist = false) معMemorySessionStorage.
خط أنابيب الكتابة
Section titled “خط أنابيب الكتابة”تُسلسل عمليات الكتابة من خلال سلسلة وعود داخلية (#persistChain) وNdjsonFileWriter.
append*يحدث حالة الذاكرة فوراً.- يتم تأجيل الحفظ حتى وجود رسالة مساعد واحدة على الأقل.
- قبل أول مساعد: تُحتفظ الإدخالات في الذاكرة؛ لا يحدث إلحاق بالملف.
- عند وجود أول مساعد: تُفرغ الجلسة الكاملة في الذاكرة إلى الملف.
- بعد ذلك: الإدخالات الجديدة تُلحق تدريجياً.
المبرر في الكود: تجنب حفظ الجلسات التي لم تُنتج أبداً استجابة مساعد.
عمليات المتانة
Section titled “عمليات المتانة”flush()يفرغ الكاتب ويستدعيfsync().- إعادة الكتابة الكاملة الذرية (
#rewriteFile) تكتب إلى ملف مؤقت، تفرغ+fsync، تغلق، ثم تعيد التسمية فوق الهدف. - تُستخدم للترحيلات،
setSessionName،rewriteEntries، عمليات النقل، وإعادة كتابة وسائط استدعاء الأدوات.
سلوك الخطأ
Section titled “سلوك الخطأ”- أخطاء الحفظ تُقفل (
#persistError) وتُعاد رميها في العمليات اللاحقة. - يُسجل الخطأ الأول مرة واحدة مع سياق ملف الجلسة.
- إغلاق الكاتب يتم بأفضل جهد لكنه ينشر أول خطأ ذي معنى.
ضوابط حجم البيانات وتخزين البيانات الكبيرة خارجياً
Section titled “ضوابط حجم البيانات وتخزين البيانات الكبيرة خارجياً”قبل حفظ الإدخالات:
- السلاسل النصية الكبيرة تُقتطع إلى
MAX_PERSIST_CHARS(500,000 حرف) مع إشعار:"[Session persistence truncated large content]"
- تُزال الحقول المؤقتة
partialJsonوjsonlEvents. - إذا كان الكائن يحتوي على كل من
contentوlineCount، يُعاد حساب عدد الأسطر بعد الاقتطاع. - كتل الصور في مصفوفات
contentمع طول base64 >= 1024 تُخزن خارجياً كمراجع بيانات كبيرة:- تُخزن كـ
blob:sha256:<hash> - تُكتب البايتات الخام إلى مخزن البيانات الكبيرة (
BlobStore.put)
- تُخزن كـ
عند التحميل، تُحل مراجع البيانات الكبيرة مرة أخرى إلى base64 لكتل الصور في message/custom_message.
تجريدات التخزين
Section titled “تجريدات التخزين”واجهة SessionStorage توفر جميع عمليات نظام الملفات المستخدمة بواسطة SessionManager:
- متزامنة:
ensureDirSync،existsSync،writeTextSync،statSync،listFilesSync - غير متزامنة:
exists،readText،readTextPrefix،writeText،rename،unlink،openWriter
التطبيقات:
FileSessionStorage: نظام ملفات حقيقي (Bun + node fs)MemorySessionStorage: تطبيق في الذاكرة مدعوم بخريطة للاختبارات/الجلسات غير المستمرة
SessionStorageWriter يكشف writeLine، flush، fsync، close، getError.
أدوات اكتشاف الجلسات
Section titled “أدوات اكتشاف الجلسات”معرفة في session-manager.ts:
getRecentSessions(sessionDir, limit)-> بيانات وصفية خفيفة لواجهة المستخدم/منتقي الجلساتfindMostRecentSession(sessionDir)-> الأحدث حسب وقت التعديلlist(cwd, sessionDir?)-> الجلسات في نطاق مشروع واحدlistAll()-> الجلسات عبر جميع نطاقات المشاريع تحت~/.xcsh/agent/sessions
استخراج البيانات الوصفية يقرأ فقط بادئة (readTextPrefix(..., 4096)) حيثما أمكن.
ذو صلة لكن مختلف: تخزين سجل الأوامر
Section titled “ذو صلة لكن مختلف: تخزين سجل الأوامر”HistoryStorage (history-storage.ts) هو نظام فرعي منفصل لـ SQLite لاسترجاع/بحث الأوامر، وليس لإعادة تشغيل الجلسة.
- قاعدة البيانات:
~/.xcsh/agent/history.db - الجدول:
history(id, prompt, created_at, cwd) - فهرس FTS5:
history_ftsمع مزامنة مُدارة بالمُحفزات - يزيل تكرار الأوامر المتتالية المتطابقة باستخدام ذاكرة مؤقتة للأمر الأخير في الذاكرة
- إدراج غير متزامن (
setImmediate) حتى لا يحجب التقاط الأمر تنفيذ الدورة
استخدم ملفات الجلسة لرسم المحادثة/إعادة تشغيل الحالة؛ واستخدم HistoryStorage لتجربة مستخدم سجل الأوامر.