الانتقال إلى المحتوى الرئيسي

إدارة الجلسات والضغط (تعمّق تقني)

تشرح هذه الوثيقة كيف يدير OpenClaw الجلسات من البداية إلى النهاية:
  • توجيه الجلسة (كيف تُطابِق الرسائل الواردة sessionKey)
  • مخزن الجلسة (sessions.json) وما الذي يتتبّعه
  • استمرارية السجل النصي (*.jsonl) وبنيته
  • نظافة السجل النصي (تصحيحات خاصة بالموفّر قبل التشغيل)
  • حدود السياق (نافذة السياق مقابل الرموز المتتبَّعة)
  • الضغط (اليدوي + التلقائي) وأين يمكن ربط أعمال ما قبل الضغط
  • الصيانة الصامتة (مثل كتابات الذاكرة التي لا ينبغي أن تُنتِج مخرجات مرئية للمستخدم)
إذا أردت نظرة عامة أعلى مستوى أولًا، ابدأ بـ:

مصدر الحقيقة: الـ Gateway

صُمّم OpenClaw حول عملية Gateway واحدة تمتلك حالة الجلسة.
  • ينبغي لواجهات المستخدم (تطبيق macOS، واجهة التحكم على الويب، TUI) الاستعلام من الـ Gateway عن قوائم الجلسات وعدّادات الرموز.
  • في الوضع البعيد، تكون ملفات الجلسة على المضيف البعيد؛ «فحص ملفات Mac المحلية» لن يعكس ما يستخدمه الـ Gateway.

طبقتان ثابتتان

يحفظ OpenClaw الجلسات في طبقتين:
  1. مخزن الجلسة (sessions.json)
    • خريطة مفتاح/قيمة: sessionKey -> SessionEntry
    • صغير، قابل للتغيير، وآمن للتحرير (أو حذف الإدخالات)
    • يتتبّع بيانات وصفية للجلسة (معرّف الجلسة الحالي، آخر نشاط، مفاتيح التبديل، عدّادات الرموز، إلخ)
  2. السجل النصي (<sessionId>.jsonl)
    • سجل إلحاقي فقط ببنية شجرية (للإدخالات id + parentId)
    • يخزّن المحادثة الفعلية + استدعاءات الأدوات + ملخّصات الضغط
    • يُستخدم لإعادة بناء سياق النموذج للأدوار اللاحقة

مواقع التخزين على القرص

لكل وكيل، على مضيف الـ Gateway:
  • المخزن: ~/.openclaw/agents/<agentId>/sessions/sessions.json
  • السجلات النصية: ~/.openclaw/agents/<agentId>/sessions/<sessionId>.jsonl
    • جلسات مواضيع Telegram: .../<sessionId>-topic-<threadId>.jsonl
يحلّ OpenClaw هذه المسارات عبر src/config/sessions.ts.

مفاتيح الجلسة (sessionKey)

يُحدِّد sessionKey «أي دلو محادثة» أنت فيه (توجيه + عزل). أنماط شائعة:
  • الدردشة الرئيسية/المباشرة (لكل وكيل): agent:<agentId>:<mainKey> (الافتراضي main)
  • مجموعة: agent:<agentId>:<channel>:group:<id>
  • غرفة/قناة (Discord/Slack): agent:<agentId>:<channel>:channel:<id> أو ...:room:<id>
  • كرون: cron:<job.id>
  • Webhook: hook:<uuid> (ما لم يتم التجاوز)
القواعد المعتمدة موثّقة في /concepts/session.

معرّفات الجلسات (sessionId)

يشير كل sessionKey إلى sessionId الحالي (ملف السجل النصي الذي يواصل المحادثة). قواعد عامة:
  • إعادة الضبط (/new، /reset) تُنشئ sessionId جديدًا لذلك sessionKey.
  • إعادة الضبط اليومية (الافتراضي 4:00 صباحًا بالتوقيت المحلي على مضيف الـ Gateway) تُنشئ sessionId جديدًا عند الرسالة التالية بعد حدّ إعادة الضبط.
  • انتهاء الخمول (session.reset.idleMinutes أو القديم session.idleMinutes) يُنشئ sessionId جديدًا عند وصول رسالة بعد نافذة الخمول. عند تفعيل اليومي + الخمول معًا، يفوز أيّهما ينتهي أولًا.
تفصيل تنفيذي: يحدث القرار في initSessionState() ضمن src/auto-reply/reply/session.ts.

مخطط مخزن الجلسة (sessions.json)

نوع قيمة المخزن هو SessionEntry في src/config/sessions.ts. الحقول الرئيسية (غير حصرية):
  • sessionId: معرّف السجل النصي الحالي (يُشتق اسم الملف منه ما لم يتم تعيين sessionFile)
  • updatedAt: طابع زمني لآخر نشاط
  • sessionFile: تجاوز اختياري لمسار السجل النصي
  • chatType: direct | group | room (يساعد واجهات المستخدم وسياسة الإرسال)
  • provider، subject، room، space، displayName: بيانات وصفية لتوسيم المجموعة/القناة
  • مفاتيح التبديل:
    • thinkingLevel، verboseLevel، reasoningLevel، elevatedLevel
    • sendPolicy (تجاوز لكل جلسة)
  • اختيار النموذج:
    • providerOverride، modelOverride، authProfileOverride
  • عدّادات الرموز (أفضل جهد/تعتمد على الموفّر):
    • inputTokens، outputTokens، totalTokens، contextTokens
  • compactionCount: عدد مرات اكتمال الضغط التلقائي لهذا مفتاح الجلسة
  • memoryFlushAt: الطابع الزمني لآخر تفريغ ذاكرة قبل الضغط
  • memoryFlushCompactionCount: عدد الضغط عند تشغيل آخر تفريغ
المخزن آمن للتحرير، لكن الـ Gateway هو المرجع: قد يعيد كتابة الإدخالات أو إعادة إحيائها أثناء تشغيل الجلسات.

بنية السجل النصي (*.jsonl)

تُدار السجلات النصية بواسطة @mariozechner/pi-coding-agent الخاص بـ SessionManager. الملف بصيغة JSONL:
  • السطر الأول: رأس الجلسة (type: "session"، يتضمن id، cwd، timestamp، و parentSession الاختياري)
  • ثم: إدخالات الجلسة مع id + parentId (شجرة)
أنواع إدخالات ملحوظة:
  • message: رسائل المستخدم/المساعد/نتيجة الأداة
  • custom_message: رسائل محقونة بواسطة الامتداد تدخل سياق النموذج (يمكن إخفاؤها عن واجهة المستخدم)
  • custom: حالة الامتداد التي لا تدخل سياق النموذج
  • compaction: ملخّص ضغط محفوظ مع firstKeptEntryId و tokensBefore
  • branch_summary: ملخّص محفوظ عند التنقّل في فرع شجري
يتعمّد OpenClaw عدم «تصحيح» السجلات النصية؛ يستخدم الـ Gateway SessionManager لقراءتها وكتابتها.

نوافذ السياق مقابل الرموز المتتبَّعة

مفهومان مختلفان مهمّان:
  1. نافذة سياق النموذج: حدّ صارم لكل نموذج (الرموز المرئية للنموذج)
  2. عدّادات مخزن الجلسة: إحصاءات متحرّكة تُكتب في sessions.json (تُستخدم لأوامر /status ولوحات المتابعة)
إذا كنت تضبط الحدود:
  • تأتي نافذة السياق من كتالوج النماذج (ويمكن تجاوزها عبر التهيئة).
  • contextTokens في المخزن هو قيمة تقدير/إبلاغ وقت التشغيل؛ لا تتعامل معه كضمان صارم.
للمزيد، راجع /token-use.

الضغط: ما هو

يلخّص الضغط المحادثات الأقدم في إدخال compaction محفوظ في السجل النصي، مع إبقاء الرسائل الحديثة سليمة. بعد الضغط، ترى الأدوار اللاحقة:
  • ملخص الدمج
  • الرسائل بعد firstKeptEntryId
الضغط مستمر (على عكس تقليم الجلسة). انظر /concepts/session-pruning.

متى يحدث الضغط التلقائي (تشغيل Pi)

في وكيل Pi المضمّن، يُفعَّل الضغط التلقائي في حالتين:
  1. استعادة من فيضان: يُرجع النموذج خطأ فيضان السياق → ضغط → إعادة المحاولة.
  2. صيانة العتبة: بعد دور ناجح، عندما:
contextTokens > contextWindow - reserveTokens حيث:
  • contextWindow هي نافذة سياق النموذج
  • reserveTokens هو الهامش المحجوز للمطالبات + مخرج النموذج التالي
هذه دلالات تشغيل Pi (يستهلك OpenClaw الأحداث، لكن Pi هو من يقرّر متى يضغط).

إعدادات الضغط (reserveTokens، keepRecentTokens)

توجد إعدادات الضغط الخاصة بـ Pi ضمن إعدادات Pi:
{
  compaction: {
    enabled: true,
    reserveTokens: 16384,
    keepRecentTokens: 20000,
  },
}
يفرض OpenClaw أيضًا حدّ أمان أدنى للتشغيلات المضمّنة:
  • إذا كان compaction.reserveTokens < reserveTokensFloor أقل، يرفعه OpenClaw.
  • الحدّ الافتراضي الأدنى هو 20000 رمزًا.
  • اضبط agents.defaults.compaction.reserveTokensFloor: 0 لتعطيل الحدّ الأدنى.
  • إذا كان أعلى بالفعل، يتركه OpenClaw كما هو.
السبب: ترك هامش كافٍ لأعمال «الصيانة» متعددة الأدوار (مثل كتابات الذاكرة) قبل أن يصبح الضغط حتميًا. التنفيذ: ensurePiCompactionReserveTokens() في src/agents/pi-settings.ts (يُستدعى من src/agents/pi-embedded-runner.ts).

الواجهات المرئية للمستخدم

يمكنك ملاحظة الضغط وحالة الجلسة عبر:
  • /status (في أي جلسة دردشة)
  • openclaw status (CLI)
  • openclaw sessions / sessions --json
  • الوضع المفصّل: 🧹 Auto-compaction complete + عدد مرات الضغط

الصيانة الصامتة (NO_REPLY)

يدعم OpenClaw أدوارًا «صامتة» للمهام الخلفية حيث لا ينبغي للمستخدم رؤية مخرجات وسيطة. الاتفاقية:
  • يبدأ المساعد مخرجه بـ NO_REPLY للإشارة إلى «عدم تسليم ردّ للمستخدم».
  • يقوم OpenClaw بإزالة/كبت ذلك في طبقة التسليم.
اعتبارًا من 2026.1.10، يقوم OpenClaw أيضًا بكبت بثّ المسودات/الكتابة عندما تبدأ قطعة جزئية بـ NO_REPLY، حتى لا تتسرّب مخرجات جزئية أثناء الدور.

«تفريغ الذاكرة» قبل الضغط (مُنفَّذ)

الهدف: قبل حدوث الضغط التلقائي، تشغيل دور وكيل صامت يكتب حالة دائمة إلى القرص (مثل memory/YYYY-MM-DD.md في مساحة عمل الوكيل) بحيث لا يستطيع الضغط محو السياق الحرج. يستخدم OpenClaw نهج التفريغ قبل العتبة:
  1. مراقبة استخدام سياق الجلسة.
  2. عند تجاوز «عتبة لينة» (أدنى من عتبة الضغط في Pi)، تشغيل توجيه صامت «اكتب الذاكرة الآن» إلى الوكيل.
  3. استخدام NO_REPLY بحيث لا يرى المستخدم شيئًا.
التهيئة (agents.defaults.compaction.memoryFlush):
  • enabled (الافتراضي: true)
  • softThresholdTokens (الافتراضي: 4000)
  • prompt (رسالة المستخدم لدور التفريغ)
  • systemPrompt (موجّه نظام إضافي يُلحق بدور التفريغ)
ملاحظات:
  • تتضمن المطالبة/موجّه النظام الافتراضيان تلميح NO_REPLY لكبت التسليم.
  • يعمل التفريغ مرة واحدة لكل دورة ضغط (يُتتبَّع في sessions.json).
  • يعمل التفريغ فقط لجلسات Pi المضمّنة (تتجاوز الخلفيات عبر CLI ذلك).
  • يُتجاوز التفريغ عندما تكون مساحة عمل الجلسة للقراءة فقط (workspaceAccess: "ro" أو "none").
  • راجع Memory لتخطيط ملفات مساحة العمل وأنماط الكتابة.
يُتيح Pi أيضًا خطّاف session_before_compact في واجهة برمجة الامتداد، لكن منطق التفريغ في OpenClaw يعيش اليوم على جانب الـ Gateway.

قائمة التحقق لاستكشاف الأخطاء وإصلاحها

  • خطأ في مفتاح الجلسة؟ خطأ في مفتاح الجلسة؟ مفتاح الجلسة خاطئ؟ ابدأ بـ /concepts/session وأكّد sessionKey في /status.
  • تخزين ضد عدم تطابق النص ؟ تخزين ضد عدم تطابق النص ؟ عدم تطابق المخزن مع السجل النصي؟ أكّد مضيف الـ Gateway ومسار المخزن من openclaw status.
  • البريد المزعج؟ تحقّق من: تحقّق من:
    • نافذة سياق النموذج (صغيرة جدًا)
    • إعدادات الضغط (reserveTokens المرتفع جدًا مقارنة بنافذة النموذج قد يسبّب ضغطًا أبكر)
    • تضخّم نتائج الأدوات: فعّل/اضبط تقليم الجلسة
  • الدوران الصامت للتسرب؟ تسرّب الأدوار الصامتة؟ أكّد أن الرد يبدأ بـ NO_REPLY (الرمز الدقيق) وأنك على إصدار يتضمن إصلاح كبت البثّ.