- الرئيسية
- Documentation
- الجلسات
- بنية شجرة الجلسة (الحالية)
بنية شجرة الجلسة (الحالية)
مرجع: session.md
يصف هذا المستند كيفية عمل تنقل شجرة الجلسة اليوم: نموذج الشجرة في الذاكرة، وقواعد حركة العقدة الطرفية، وسلوك التفريع، وتكامل الإضافات والأحداث.
ما هذا النظام الفرعي
Section titled “ما هذا النظام الفرعي”يُخزَّن الجلسة كسجل إدخالات يُلحَق فقط، غير أن السلوك أثناء التشغيل يعتمد على الشجرة:
- كل إدخال غير ترويسي له
idوparentId. - الموضع النشط هو
leafIdفيSessionManager. - يؤدي إلحاق إدخال دائمًا إلى إنشاء فرع من العقدة الطرفية الحالية.
- التفريع لا يُعيد كتابة السجل التاريخي؛ بل يغير فقط المكان الذي تشير إليه العقدة الطرفية قبل الإلحاق التالي.
الملفات الرئيسية:
src/session/session-manager.ts— نموذج بيانات الشجرة، والاجتياز، وحركة العقدة الطرفية، واستخراج الفرع/الجلسةsrc/session/agent-session.ts— تدفق تنقل/tree، والتلخيص، وإرسال الخطافات/الأحداثsrc/modes/components/tree-selector.ts— سلوك واجهة الشجرة التفاعلية والتصفيةsrc/modes/controllers/selector-controller.ts— تنسيق أداة الاختيار لـ/treeو/branchsrc/modes/controllers/input-controller.ts— توجيه الأوامر (/tree، و/branch، وسلوك الضغط المزدوج على Escape)src/session/messages.ts— تحويل إدخالاتbranch_summaryوcompactionوcustom_messageإلى رسائل سياق LLM
نموذج بيانات الشجرة في SessionManager
Section titled “نموذج بيانات الشجرة في SessionManager”الفهارس أثناء التشغيل:
#byId: Map<string, SessionEntry>— بحث سريع عن أي إدخال#leafId: string | null— الموضع الحالي في الشجرة#labelsById: Map<string, string>— التسميات المحلولة حسب معرّف الإدخال المستهدف
واجهات برمجة شجرة الشجرة:
getBranch(fromId?)يجتاز روابط الأصل حتى الجذر ويعيد مسار الجذر→العقدةgetTree()يعيدSessionTreeNode[](entry، وchildren، وlabel)- تصبح روابط الأصل مصفوفات أبناء
- تُعامَل الإدخالات التي تفتقر إلى أصول كجذور
- يُرتَّب الأبناء من الأقدم إلى الأحدث حسب الطابع الزمني
getChildren(parentId)يعيد الأبناء المباشرينgetLabel(id)يُحلّ التسمية الحالية منlabelsById
getTree() هي إسقاط أثناء التشغيل؛ يبقى الاستمرار عبر إدخالات JSONL المُلحَقة فقط.
دلالات حركة العقدة الطرفية
Section titled “دلالات حركة العقدة الطرفية”ثمة ثلاثة أساسيات لحركة العقدة الطرفية:
-
branch(entryId)- يتحقق من وجود الإدخال
- يضبط
leafId = entryId - لا يُكتَب أي إدخال جديد
-
resetLeaf()- يضبط
leafId = null - الإلحاق التالي ينشئ إدخال جذر جديد (
parentId = null)
- يضبط
-
branchWithSummary(branchFromId, summary, details?, fromExtension?)- يقبل
branchFromId: string | null - يضبط
leafId = branchFromId - يُلحق إدخال
branch_summaryكفرع من تلك العقدة الطرفية - عندما يكون
branchFromIdهوnull، يُخزَّنfromIdبصيغة"root"
- يقبل
سلوك تنقل /tree (ملف الجلسة ذاته)
Section titled “سلوك تنقل /tree (ملف الجلسة ذاته)”AgentSession.navigateTree() هي تنقل، وليست تفريعًا لملف.
التدفق:
- التحقق من الهدف وحساب المسار المتروك (
collectEntriesForBranchSummary) - إرسال
session_before_treeمعTreePreparation - تلخيص الإدخالات المتروكة اختياريًا (ملخص مقدَّم من الخطاف أو ملخص مدمج)
- حساب هدف العقدة الطرفية الجديدة:
- اختيار رسالة مستخدم: تنتقل العقدة الطرفية إلى أصلها، وتُعاد نص الرسالة لتعبئة المحرر مسبقًا
- اختيار custom_message: نفس قاعدة رسالة المستخدم (العقدة الطرفية = الأصل، والنص يُعبّئ المحرر مسبقًا)
- اختيار أي إدخال آخر: العقدة الطرفية = معرف الإدخال المختار
- تطبيق حركة العقدة الطرفية:
- مع ملخص:
branchWithSummary(newLeafId, ...) - بدون ملخص وكان
newLeafId === null:resetLeaf() - وإلا:
branch(newLeafId)
- مع ملخص:
- إعادة بناء سياق الوكيل من العقدة الطرفية الجديدة وإرسال
session_tree
مهم: تُربط إدخالات الملخص بـ موضع التنقل الجديد، لا بنهاية الفرع المتروك.
سلوك /branch (ملف جلسة جديد)
Section titled “سلوك /branch (ملف جلسة جديد)”/branch و/tree مختلفان عمدًا:
/treeينقل داخل ملف الجلسة الحالي./branchينشئ ملف فرع جلسة جديدًا (أو استبدالًا في الذاكرة لوضع عدم الاستمرار).
تدفق /branch الموجه للمستخدم (SelectorController.showUserMessageSelector ← AgentSession.branch):
- يجب أن يكون مصدر الفرع رسالة مستخدم.
- يُستخرج نص المستخدم المختار لتعبئة المحرر مسبقًا.
- إذا كانت رسالة المستخدم المختارة جذرًا (
parentId === null): يبدأ جلسة جديدة عبرnewSession({ parentSession: previousSessionFile }). - وإلا:
createBranchedSession(selectedEntry.parentId)لتفريع السجل حتى حد المطالبة المختارة.
تفاصيل SessionManager.createBranchedSession(leafId):
- يبني مسار الجذر→العقدة الطرفية عبر
getBranch(leafId)؛ يُلقي خطأ إذا كان مفقودًا. - يستبعد إدخالات
labelالموجودة من المسار المنسوخ. - يُعيد بناء إدخالات تسمية جديدة من
labelsByIdالمحلولة للإدخالات التي تبقى في المسار. - الوضع المستمر: يكتب ملف JSONL جديدًا ويُبدّل المدير إليه؛ يعيد مسار الملف الجديد.
- الوضع في الذاكرة: يستبدل الإدخالات في الذاكرة؛ يعيد
undefined.
إعادة بناء السياق وتكامل الملخص/المخصص
Section titled “إعادة بناء السياق وتكامل الملخص/المخصص”buildSessionContext() (في session-manager.ts) يُحلّ مسار الجذر→العقدة الطرفية النشطة ويبني حالة سياق LLM الفعلية:
- يتتبع أحدث حالة تفكير/نموذج/وضع/ttsr على المسار.
- يتعامل مع أحدث ضغط على المسار:
- يُرسل ملخص الضغط أولًا
- يُعيد تشغيل الرسائل المحتفظ بها من
firstKeptEntryIdحتى نقطة الضغط - ثم يُعيد تشغيل الرسائل بعد الضغط
- يشمل إدخالات
branch_summaryوcustom_messageكأجسامAgentMessage.
ثم يُعيّن session/messages.ts هذه الأنواع من الرسائل لمدخلات النموذج:
- يصبح
branchSummaryوcompactionSummaryرسائل سياق ذات قالب بدور المستخدم - يصبح
custom/hookMessageرسائل محتوى بدور المستخدم
وبالتالي تغيّر حركة الشجرة السياق بتغيير مسار العقدة الطرفية النشطة، لا بتعديل الإدخالات القديمة.
التسميات وسلوك واجهة الشجرة
Section titled “التسميات وسلوك واجهة الشجرة”استمرار التسميات:
appendLabelChange(targetId, label?)يكتب إدخالاتlabelعلى سلسلة العقدة الطرفية الحالية.- يُحدَّث
labelsByIdفورًا (ضبط أو حذف). - يُحلّ
getTree()التسمية الحالية على كل عقدة مُعادة.
سلوك أداة اختيار الشجرة (tree-selector.ts):
- يُسطّح الشجرة للتنقل، ويحتفظ بإبراز المسار النشط، ويُولي الأولوية لعرض الفرع النشط أولًا.
- يدعم أوضاع التصفية:
default، وno-tools، وuser-only، وlabeled-only، وall. - يدعم البحث بالنص الحر في المحتوى الدلالي المُقيَّم.
- يفتح
Shift+Lتحرير التسمية المضمّن ويكتب عبرappendLabelChange.
توجيه الأوامر:
/treeيفتح دائمًا أداة اختيار الشجرة./branchيفتح أداة اختيار رسالة المستخدم إلا إذا كانdoubleEscapeAction=tree، وفي هذه الحالة يستخدم أيضًا واجهة أداة اختيار الشجرة.
نقاط تواصل الإضافات والخطافات لعمليات الشجرة
Section titled “نقاط تواصل الإضافات والخطافات لعمليات الشجرة”واجهة برمجة الإضافات وقت الأمر (ExtensionCommandContext):
branch(entryId)— إنشاء ملف جلسة متفرّعnavigateTree(targetId, { summarize? })— التنقل داخل الشجرة/الملف الحالي
الأحداث حول تنقل الشجرة:
session_before_tree- يستقبل
TreePreparation:targetIdoldLeafIdcommonAncestorIdentriesToSummarizeuserWantsSummary
- قد يُلغي التنقل
- قد يُقدّم حمولة ملخص تُستخدم بدلًا من الملخص المدمج
- يستقبل إشارة إلغاء
signal(مسار الإلغاء بـ Escape)
- يستقبل
session_tree- يُرسل
newLeafId، وoldLeafId - يتضمن
summaryEntryعند إنشاء ملخص fromExtensionيُشير إلى مصدر الملخص
- يُرسل
خطافات دورة الحياة المجاورة ذات الصلة:
session_before_branch/session_branchلتدفق/branchsession_before_compact، وsession.compacting، وsession_compactلإدخالات الضغط التي تؤثر لاحقًا على إعادة بناء سياق الشجرة
القيود الحقيقية وحالات الحواف
Section titled “القيود الحقيقية وحالات الحواف”- لا يمكن لـ
branch()استهدافnull؛ استخدمresetLeaf()لحالة الجذر قبل الإدخال الأول. - تدعم
branchWithSummary()الهدفnullوتُسجّلfromId: "root". - اختيار العقدة الطرفية الحالية في أداة اختيار الشجرة لا يُحدث أي تأثير.
- يتطلب التلخيص نموذجًا نشطًا؛ في حال غيابه، يفشل التنقل مع التلخيص فورًا.
- إذا أُلغي التلخيص، يُلغى التنقل وتبقى العقدة الطرفية دون تغيير.
- لا تُعيد الجلسات في الذاكرة أبدًا مسار ملف فرع من
createBranchedSession.
التوافق مع الإصدارات القديمة المازال موجودًا
Section titled “التوافق مع الإصدارات القديمة المازال موجودًا”لا تزال ترحيلات الجلسة تعمل عند التحميل:
- v1→v2 يضيف
id/parentIdويحوّل مرساة فهرس الضغط القديمة إلى مرساة معرّف - v2→v3 يُرحّل دور
hookMessageالقديم إلىcustom
السلوك الحالي أثناء التشغيل هو دلالات شجرة الإصدار الثالث بعد الترحيل.