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

إدارة الجلسات والضغط (شرح تفصيلي)

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

مصدر الحقيقة: البوابة

تم تصميم OpenClaw حول عملية Gateway واحدة تمتلك حالة الجلسة.
  • يجب على واجهات المستخدم (تطبيق macOS، وواجهة الويب Control UI، وTUI) الاستعلام من البوابة عن قوائم الجلسات وعدد الرموز.
  • في الوضع البعيد، تكون ملفات الجلسة على المضيف البعيد؛ لذا فإن “فحص ملفات Mac المحلية” لن يعكس ما تستخدمه البوابة.

طبقتا الاستمرارية

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

المواقع على القرص

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

صيانة المخزن وعناصر التحكم في القرص

تحتوي استمرارية الجلسة على عناصر تحكم صيانة تلقائية (session.maintenance) لـ sessions.json وعناصر النص:
  • mode: ‏warn (افتراضي) أو enforce
  • pruneAfter: حد عمر الإدخالات القديمة (الافتراضي 30d)
  • maxEntries: الحد الأقصى للإدخالات في sessions.json (الافتراضي 500)
  • rotateBytes: تدوير sessions.json عند زيادة حجمه (الافتراضي 10mb)
  • resetArchiveRetention: مدة الاحتفاظ بأرشيفات النص *.reset.<timestamp> (الافتراضي: نفس pruneAfter؛ وتعطّل false التنظيف)
  • maxDiskBytes: ميزانية اختيارية لدليل الجلسات
  • highWaterBytes: هدف اختياري بعد التنظيف (الافتراضي 80% من maxDiskBytes)
ترتيب التنفيذ لتنظيف ميزانية القرص (mode: "enforce"):
  1. إزالة أقدم عناصر النص المؤرشفة أو اليتيمة أولًا.
  2. إذا ظل الاستخدام فوق الهدف، يتم إخراج أقدم إدخالات الجلسات وملفات النص الخاصة بها.
  3. الاستمرار حتى يصبح الاستخدام عند 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 وelevatedLevel
    • sendPolicy (تجاوز لكل جلسة)
  • اختيار النموذج:
    • providerOverride وmodelOverride وauthProfileOverride
  • عدادات الرموز (أفضل جهد / حسب الموفّر):
    • inputTokens وoutputTokens وtotalTokens وcontextTokens
  • compactionCount: عدد مرات اكتمال الضغط التلقائي لهذا sessionKey
  • memoryFlushAt: الطابع الزمني لآخر تفريغ ذاكرة قبل الضغط
  • memoryFlushCompactionCount: عدد مرات الضغط عند آخر تشغيل للتفريغ
المخزن آمن للتحرير، لكن البوابة هي الجهة المخولة: قد تعيد كتابة الإدخالات أو إعادة ترطيبها أثناء تشغيل الجلسات.

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

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

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

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

الضغط: ما هو

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

حدود أجزاء الضغط وإقران الأدوات

عندما يقسم OpenClaw نصًا طويلًا إلى أجزاء ضغط، فإنه يحافظ على اقتران استدعاءات أدوات المساعد مع إدخالات toolResult المطابقة لها.
  • إذا وقع تقسيم حصة الرموز بين استدعاء أداة ونتيجتها، فإن OpenClaw يزيح الحد إلى رسالة استدعاء أداة المساعد بدلًا من فصل الزوج.
  • إذا كانت كتلة toolResult اللاحقة ستدفع الجزء فوق الهدف، فإن OpenClaw يحافظ على كتلة الأداة المعلقة هذه ويبقي الذيل غير الملخَّص كما هو.
  • لا تُبقي كتل استدعاء الأدوات الملغاة/الخاطئة انقسامًا معلقًا مفتوحًا.

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

في وكيل Pi المضمن، يتم تشغيل الضغط التلقائي في حالتين:
  1. استرداد تجاوز الحد: يعيد النموذج خطأ تجاوز سياق (request_too_large أو context length exceeded أو input exceeds the maximum number of tokens أو input token count exceeds the maximum number of input tokens أو input is too long for the model أو ollama error: context length exceeded، وأشكالًا مشابهة بصياغة الموفّر) ← ضغط ← إعادة محاولة.
  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).

موفّرو ضغط قابلون للتوصيل

يمكن للإضافات تسجيل موفر ضغط عبر registerCompactionProvider() في API الخاص بالإضافة. عندما يتم تعيين agents.defaults.compaction.provider إلى معرّف موفر مسجل، يقوم امتداد الحماية بتفويض التلخيص إلى ذلك الموفر بدلًا من خط أنابيب summarizeInStages المضمن.
  • provider: معرّف إضافة موفر ضغط مسجلة. اتركه غير معيّن لاستخدام تلخيص LLM الافتراضي.
  • يؤدي تعيين provider إلى فرض mode: "safeguard".
  • تتلقى الموفّرات تعليمات الضغط نفسها وسياسة الحفاظ على المعرّفات نفسها كما في المسار المضمن.
  • ما تزال الحماية تحافظ على سياق لاحقة الدورات الحديثة والدورات المنقسمة بعد خرج الموفّر.
  • إذا فشل الموفّر أو أعاد نتيجة فارغة، يعود OpenClaw تلقائيًا إلى التلخيص المضمن باستخدام LLM.
  • تُعاد إشارات الإيقاف/انتهاء المهلة كما هي (ولا تُبتلع) احترامًا لإلغاء المستدعي.
المصدر: src/plugins/compaction-provider.ts، ‏src/agents/pi-hooks/compaction-safeguard.ts.

الأسطح المرئية للمستخدم

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

الترتيب الصامت (NO_REPLY)

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

”تفريغ الذاكرة” قبل الضغط (منفذ)

الهدف: قبل حدوث الضغط التلقائي، يتم تشغيل دورة وكيلية صامتة تكتب حالة دائمة إلى القرص (مثل memory/YYYY-MM-DD.md في مساحة عمل الوكيل) بحيث لا يستطيع الضغط محو السياق الحرج. يستخدم OpenClaw نهج التفريغ قبل الحد:
  1. راقب استخدام سياق الجلسة.
  2. عندما يتجاوز “حدًا مرنًا” (أقل من حد ضغط Pi)، شغّل توجيهًا صامتًا “اكتب الذاكرة الآن” إلى الوكيل.
  3. استخدم الرمز الصامت الدقيق NO_REPLY / 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 في API الامتداد، لكن منطق التفريغ في OpenClaw يعيش حاليًا على جانب البوابة.

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

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