غوص عميق في إدارة الجلسات
يشرح هذا المستند كيفية إدارة OpenClaw للجلسات من البداية إلى النهاية:
- توجيه الجلسات (كيفية تعيين الرسائل الواردة إلى
sessionKey) - مستودع الجلسات (
sessions.json) وما يتعقبه - استمرارية النص (
*.jsonl) وهيكله - تنظيف النص (الإصلاحات الخاصة بالمزود قبل التشغيل)
- حدود السياق (نافذة السياق مقابل الرموز المتعقبة)
- الضغط (الضغط اليدوي + الآلي) وأين يتم ربط العمل قبل الضغط
- الصيانة الصامتة (مثل كتابات الذاكرة التي لا يجب أن تنتج مخرجات مرئية للمستخدم)
إذا كنت تريد نظرة عامة عالية المستوى أولاً، ابدأ بـ:
مصدر الحقيقة: البوابة
تم تصميم OpenClaw حول عملية بوابة واحدة تمتلك حالة الجلسة.
- واجهات المستخدم (تطبيق macOS، واجهة التحكم على الويب، TUI) يجب أن تستعلم من البوابة للحصول على قوائم الجلسات وأعداد الرموز.
- في الوضع البعيد، ملفات الجلسات موجودة على المضيف البعيد؛ "التحقق من ملفات Mac المحلية الخاصة بك" لن يعكس ما تستخدمه البوابة.
طبقتا استمرارية
يحافظ OpenClaw على الجلسات في طبقتين:
- مستودع الجلسات (
sessions.json)- خريطة مفتاح/قيمة:
sessionKey -> SessionEntry - صغير، قابل للتعديل، آمن للتحرير (أو حذف الإدخالات)
- يتعقب بيانات وصفية للجلسة (معرف الجلسة الحالي، آخر نشاط، مفاتيح التبديل، عدادات الرموز، إلخ.)
- خريطة مفتاح/قيمة:
- النص (
<sessionId>.jsonl)- نص مضاف فقط مع بنية شجرية (للإدخالات
id+parentId) - يخزن المحادثة الفعلية + استدعاءات الأدوات + ملخصات الضغط
- يُستخدم لإعادة بناء سياق النموذج للأدوار المستقبلية
- نص مضاف فقط مع بنية شجرية (للإدخالات
المواقع على القرص
لكل وكيل، على مضيف البوابة:
- المستودع:
~/.openclaw/agents/<agentId>/sessions/sessions.json - النصوص:
~/.openclaw/agents/<agentId>/sessions/<sessionId>.jsonl- جلسات موضوع Telegram:
.../<sessionId>-topic-<threadId>.jsonl
- جلسات موضوع Telegram:
يحل OpenClaw هذه المواقع عبر src/config/sessions.ts.
صيانة المستودع وضوابط القرص
للاستمرارية في الجلسات ضوابط صيانة تلقائية (session.maintenance) لـ sessions.json وقطع النصوص:
mode:warn(الافتراضي) أوenforcepruneAfter: حد عمر الإدخالات القديمة (الافتراضي30d)maxEntries: حد أقصى للإدخالات فيsessions.json(الافتراضي500)rotateBytes: تدويرsessions.jsonعندما يتجاوز الحجم (الافتراضي10mb)resetArchiveRetention: الاحتفاظ بأرشيفات النصوص*.reset.<timestamp>(الافتراضي: نفسpruneAfter؛falseيعطل التنظيف)maxDiskBytes: ميزانية اختيارية لمجلد الجلساتhighWaterBytes: هدف اختياري بعد التنظيف (الافتراضي80%منmaxDiskBytes)
ترتيب التنفيذ لتنظيف ميزانية القرص (mode: "enforce"):
- إزالة أقدم قطع النصوص المؤرشفة أو المهملة أولاً.
- إذا كان الاستخدام لا يزال فوق الهدف، إزالة أقدم إدخالات الجلسات وملفات النصوص الخاصة بها.
- الاستمرار حتى يصبح الاستخدام عند أو أقل من
highWaterBytes.
في mode: "warn"، يبلغ OpenClaw عن عمليات الإزالة المحتملة ولكنه لا يعدل المستودع/الملفات. قم بتشغيل الصيانة عند الطلب:
openclaw sessions cleanup --dry-run
openclaw sessions cleanup --enforce
جلسات Cron وسجلات التشغيل
تشغيلات cron المعزولة تنشئ أيضًا إدخالات جلسات/نصوص، ولها ضوابط احتفاظ مخصصة:
cron.sessionRetention(الافتراضي24h) يزيل جلسات تشغيل cron المعزولة القديمة من مستودع الجلسات (falseيعطل).cron.runLog.maxBytes+cron.runLog.keepLinesيزيلان ملفات~/.openclaw/cron/runs/<jobId>.jsonl(الافتراضي:2_000_000بايت و2000سطر).
مفاتيح الجلسات (sessionKey)
يحدد sessionKey دلو المحادثة الذي أنت فيه (التوجيه + العزل). الأنماط الشائعة:
- الدردشة الرئيسية/المباشرة (لكل وكيل):
agent:<agentId>:<mainKey>(الافتراضيmain) - المجموعة:
agent:<agentId>:<channel>:group:<id> - الغرفة/القناة (Discord/Slack):
agent:<agentId>:<channel>:channel:<id>أو...:room:<id> - Cron:
cron:<job.id> - Webhook:
hook:<uuid>(ما لم يتم تجاوزه)
القواعد الأساسية موثقة في /concepts/session.
معرفات الجلسات (sessionId)
يشير كل sessionKey إلى sessionId حالي (ملف النص الذي يستمر في المحادثة). قواعد عامة:
- إعادة التعيين (
/new,/reset) ينشئsessionIdجديدًا لذلكsessionKey. - إعادة التعيين اليومي (الافتراضي 4:00 صباحًا بالتوقيت المحلي على مضيف البوابة) ينشئ
sessionIdجديدًا عند الرسالة التالية بعد حد إعادة التعيين. - انتهاء فترة الخمول (
session.reset.idleMinutesأو الموروثsession.idleMinutes) ينشئsessionIdجديدًا عند وصول رسالة بعد نافذة الخمول. عندما يتم تكوين كل من اليومي والخمول، أيهما ينتهي أولاً يفوز. - حماية تفرع الأب للخيط (
session.parentForkMaxTokens، الافتراضي100000) يتخطى تفرع نص الأب عندما تكون جلسة الأب كبيرة بالفعل؛ يبدأ الخيط الجديد من جديد. اضبط0لتعطيل.
تفصيل التنفيذ: يتم اتخاذ القرار في 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,elevatedLevelsendPolicy(تجاوز لكل جلسة)
- اختيار النموذج:
providerOverride,modelOverride,authProfileOverride
- عدادات الرموز (أفضل جهد / تعتمد على المزود):
inputTokens,outputTokens,totalTokens,contextTokens
compactionCount: عدد مرات اكتمال الضغط الآلي لمفتاح الجلسة هذاmemoryFlushAt: طابع زمني لآخر تفريغ للذاكرة قبل الضغطmemoryFlushCompactionCount: عدد الضغط عند تشغيل آخر تفريغ
المستودع آمن للتحرير، لكن البوابة هي السلطة: قد تعيد كتابة أو إعادة تعبئة الإدخالات أثناء تشغيل الجلسات.
هيكل النص (*.jsonl)
يتم إدارة النصوص بواسطة SessionManager الخاص بـ @mariozechner/pi-coding-agent. الملف هو JSONL:
- السطر الأول: رأس الجلسة (
type: "session"، يتضمنid,cwd,timestamp, اختياريparentSession) - ثم: إدخالات الجلسة مع
id+parentId(شجرة)
أنواع الإدخالات البارزة:
message: رسائل المستخدم/المساعد/نتيجة الأداةcustom_message: رسائل محقونة بواسطة الامتداد تدخل سياق النموذج (يمكن إخفاؤها عن واجهة المستخدم)custom: حالة امتداد لا تدخل سياق النموذجcompaction: ملخص ضغط مستمر معfirstKeptEntryIdوtokensBeforebranch_summary: ملخص مستمر عند التنقل في فرع شجرة
لا يقوم OpenClaw عمدًا "بإصلاح" النصوص؛ تستخدم البوابة SessionManager لقراءتها/كتابتها.
نوافذ السياق مقابل الرموز المتعقبة
مفهومان مختلفان مهمان:
- نافذة سياق النموذج: حد صارم لكل نموذج (الرموز المرئية للنموذج)
- عدادات مستودع الجلسات: إحصائيات مستمرة مكتوبة في
sessions.json(تُستخدم لـ /status ولوحات التحكم)
إذا كنت تضبط الحدود:
- تأتي نافذة السياق من كتالوج النموذج (ويمكن تجاوزها عبر التكوين).
contextTokensفي المستودع هو تقدير/قيمة إبلاغ وقت التشغيل؛ لا تعامله كضمان صارم.
لمزيد من المعلومات، انظر /token-use.
الضغط: ما هو
يُلخص الضغط المحادثة الأقدم في إدخال compaction مستمر في النص ويبقي الرسائل الحديثة سليمة. بعد الضغط، ترى الأدوار المستقبلية:
- ملخص الضغط
- الرسائل بعد
firstKeptEntryId
الضغط مستمر (على عكس تقليم الجلسات). انظر /concepts/session-pruning.
متى يحدث الضغط الآلي (وقت تشغيل Pi)
في وكيل Pi المضمن، يتم تشغيل الضغط الآلي في حالتين:
- استعادة الفيضان: يُرجع النموذج خطأ فيضان السياق → ضغط → إعادة المحاولة.
- صيانة العتبة: بعد دور ناجح، عندما:
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 نهج التفريغ قبل العتبة:
- مراقبة استخدام سياق الجلسة.
- عندما يتجاوز "عتبة ناعمة" (أقل من عتبة ضغط Pi)، قم بتشغيل توجيه صامت "اكتب الذاكرة الآن" للوكيل.
- استخدم
NO_REPLYحتى لا يرى المستخدم شيئًا.
التكوين (agents.defaults.compaction.memoryFlush):
enabled(الافتراضي:true)softThresholdTokens(الافتراضي:4000)prompt(رسالة المستخدم لدور التفريغ)systemPrompt(طلب نظام إضافي مرفق لدور التفريغ)
ملاحظات:
- يتضمن الطلب الافتراضي/طلب النظام الافتراضي تلميح
NO_REPLYلكبح التسليم. - يعمل التفريغ مرة واحدة لكل دورة ضغط (يتم تعقبه في
sessions.json). - يعمل التفريغ فقط لجلسات Pi المضمنة (تتخطى واجهات سطر الأوامر الخلفية ذلك).
- يتم تخطي التفريغ عندما تكون مساحة عمل الجلسة للقراءة فقط (
workspaceAccess: "ro"أو"none"). - انظر الذاكرة لتخطيط ملف مساحة العمل وأنماط الكتابة.
يعرض Pi أيضًا خطاف session_before_compact في واجهة برمجة تطبيقات الامتداد، لكن منطق التفريغ في OpenClaw يعيش على جانب البوابة اليوم.
قائمة التحقق لاستكشاف الأخطاء وإصلاحها
- مفتاح الجلسة خاطئ؟ ابدأ بـ /concepts/session وتأكد من
sessionKeyفي/status. - عدم تطابق بين المستودع والنص؟ تأكد من مضيف البوابة ومسار المستودع من
openclaw status. - ضغط متكرر؟ تحقق من:
- نافذة سياق النموذج (صغيرة جدًا)
- إعدادات الضغط (
reserveTokensمرتفع جدًا بالنسبة لنافذة النموذج يمكن أن يسبب ضغطًا مبكرًا) - تضخم نتيجة الأداة: قم بتشغيل/ضبط تقليم الجلسات
- تسرب في الأدوار الصامتة؟ تأكد من أن الرد يبدأ بـ
NO_REPLY(الرمز المطابق تمامًا) وأنك على إصدار يتضمن إصلاح كبح التدفق.