الجلسات والذاكرة

إدارة الجلسات

تعامل OpenClaw مع جلسة محادثة مباشرة واحدة لكل وكيل على أنها الأساسية. تنهار المحادثات المباشرة إلى agent:<agentId>:<mainKey> (الافتراضي main)، بينما تحصل محادثات المجموعة/القناة على مفاتيح خاصة بها. يتم احترام session.mainKey. استخدم session.dmScope للتحكم في كيفية تجميع الرسائل المباشرة:

  • main (الافتراضي): جميع الرسائل المباشرة تشارك الجلسة الرئيسية لضمان الاستمرارية.
  • per-peer: عزل حسب هوية المرسل عبر القنوات.
  • per-channel-peer: عزل حسب القناة + المرسل (موصى به للصناديق الواردة متعددة المستخدمين).
  • per-account-channel-peer: عزل حسب الحساب + القناة + المرسل (موصى به للصناديق الواردة متعددة الحسابات). استخدم session.identityLinks لتعيين هويات الأقران ذات البادئة الخاصة بالمزود إلى هوية قياسية بحيث يشارك نفس الشخص جلسة رسائل مباشرة عبر القنوات عند استخدام per-peer، أو per-channel-peer، أو per-account-channel-peer.

وضع الرسائل المباشرة الآمن (موصى به للإعدادات متعددة المستخدمين)

تحذير أمني: إذا كان وكيلك يمكنه استقبال رسائل مباشرة من عدة أشخاص، فيجب أن تفكر جدياً في تمكين وضع الرسائل المباشرة الآمن. بدونه، يشارك جميع المستخدمين نفس سياق المحادثة، مما قد يؤدي إلى تسريب معلومات خاصة بين المستخدمين.

مثال على المشكلة مع الإعدادات الافتراضية:

  • أليس (<SENDER_A>) ترسل رسالة إلى وكيلك حول موضوع خاص (على سبيل المثال، موعد طبي)
  • بوب (<SENDER_B>) يرسل رسالة إلى وكيلك يسأل فيها "عماذا كنا نتحدث؟"
  • لأن كلا الرسالتين المباشرتين تشاركان نفس الجلسة، قد يجيب النموذج بوب باستخدام السياق السابق لأليس.

الحل: اضبط dmScope لعزل الجلسات لكل مستخدم:

// ~/.openclaw/openclaw.json
{
  session: {
    // وضع الرسائل المباشرة الآمن: عزل سياق الرسائل المباشرة لكل قناة + مرسل.
    dmScope: "per-channel-peer",
  },
}

متى يتم تمكين هذا:

  • لديك موافقات إقران لأكثر من مرسل واحد
  • تستخدم قائمة السماح للرسائل المباشرة تحتوي على عدة إدخالات
  • تضبط dmPolicy: "open"
  • يمكن لعدة أرقام هواتف أو حسابات مراسلة وكيلك

ملاحظات:

  • الافتراضي هو dmScope: "main" للاستمرارية (جميع الرسائل المباشرة تشارك الجلسة الرئيسية). هذا مناسب للإعدادات ذات المستخدم الواحد.
  • عملية الإعداد المحلية لـ CLI تكتب session.dmScope: "per-channel-peer" افتراضياً عندما لا تكون محددة (يتم الحفاظ على القيم الصريحة الموجودة).
  • للصناديق الواردة متعددة الحسابات على نفس القناة، يُفضل استخدام per-account-channel-peer.
  • إذا اتصل بك نفس الشخص على قنوات متعددة، استخدم session.identityLinks لدمج جلسات الرسائل المباشرة الخاصة به في هوية قياسية واحدة.
  • يمكنك التحقق من إعدادات الرسائل المباشرة الخاصة بك باستخدام openclaw security audit (انظر الأمان).

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

جميع حالة الجلسة مملوكة للبوابة (الـ "OpenClaw الرئيسي"). يجب على عملاء واجهة المستخدم (تطبيق macOS، وWebChat، إلخ.) الاستعلام من البوابة للحصول على قوائم الجلسات وأعداد الرموز بدلاً من قراءة الملفات المحلية.

  • في الوضع البعيد، مخزن الجلسات الذي تهتم به موجود على مضيف البوابة البعيد، وليس على جهاز Mac الخاص بك.
  • أعداد الرموز المعروضة في واجهات المستخدم تأتي من حقول المخزن في البوابة (inputTokens, outputTokens, totalTokens, contextTokens). لا يقوم العملاء بتحليل نصوص JSONL "لتصحيح" الإجماليات.

أين توجد الحالة

  • على مضيف البوابة:
    • ملف المخزن: ~/.openclaw/agents/<agentId>/sessions/sessions.json (لكل وكيل).
  • النصوص: ~/.openclaw/agents/<agentId>/sessions/<SessionId>.jsonl (جلسات مواضيع Telegram تستخدم .../<SessionId>-topic-<threadId>.jsonl).
  • المخزن عبارة عن خريطة sessionKey -> { sessionId, updatedAt, ... }. حذف الإدخالات آمن؛ يتم إعادة إنشائها عند الطلب.
  • قد تتضمن إدخالات المجموعة displayName, channel, subject, room, و space لوضع تسميات للجلسات في واجهات المستخدم.
  • تتضمن إدخالات الجلسة بيانات وصفية origin (تسمية + تلميحات التوجيه) حتى تتمكن واجهات المستخدم من شرح مصدر الجلسة.
  • لا تقرأ OpenClaw مجلدات جلسات Pi/Tau القديمة.

الصيانة

تطبق OpenClaw صيانة مخزن الجلسات للحفاظ على sessions.json وقطع النصوص محدودة مع مرور الوقت.

الإعدادات الافتراضية

  • session.maintenance.mode: warn
  • session.maintenance.pruneAfter: 30d
  • session.maintenance.maxEntries: 500
  • session.maintenance.rotateBytes: 10mb
  • session.maintenance.resetArchiveRetention: الافتراضي هو pruneAfter (30d)
  • session.maintenance.maxDiskBytes: غير مضبوط (معطل)
  • session.maintenance.highWaterBytes: الافتراضي هو 80% من maxDiskBytes عند تمكين الميزانية

كيفية عملها

تعمل الصيانة أثناء كتابات مخزن الجلسات، ويمكنك تشغيلها عند الطلب باستخدام openclaw sessions cleanup.

  • mode: "warn": يبلغ عما سيتم إزالته ولكن لا يغير الإدخالات/النصوص.
  • mode: "enforce": يطبق التنظيف بهذا الترتيب:
    1. إزالة الإدخالات القديمة الأقدم من pruneAfter
    2. تحديد عدد الإدخالات بـ maxEntries (الأقدم أولاً)
    3. أرشفة ملفات النصوص للإدخالات المزالة التي لم يعد يتم الإشارة إليها
    4. تطهير الأرشيفات القديمة *.deleted.<timestamp> و *.reset.<timestamp> حسب سياسة الاحتفاظ
    5. تدوير sessions.json عندما يتجاوز rotateBytes
    6. إذا تم ضبط maxDiskBytes، فرض ميزانية القرص نحو highWaterBytes (أقدم القطع أولاً، ثم أقدم الجلسات)

تحذير الأداء للمخازن الكبيرة

مخازن الجلسات الكبيرة شائعة في الإعدادات عالية الحجم. عمل الصيانة هو عمل في مسار الكتابة، لذا يمكن للمخازن الكبيرة جداً زيادة زمن الاستجابة للكتابة. ما يزيد التكلفة أكثر:

  • قيم session.maintenance.maxEntries عالية جداً
  • نوافذ pruneAfter طويلة تحتفظ بالإدخالات القديمة
  • العديد من قطع النصوص/الأرشيفات في ~/.openclaw/agents/<agentId>/sessions/
  • تمكين ميزانيات القرص (maxDiskBytes) دون حدود تقليم/سقف معقولة

ما يجب فعله:

  • استخدم mode: "enforce" في الإنتاج بحيث يكون النمو محدوداً تلقائياً
  • اضبط كلاً من حدود الوقت والعدد (pruneAfter + maxEntries)، وليس واحداً فقط
  • اضبط maxDiskBytes + highWaterBytes لحدود عليا صارمة في النشرات الكبيرة
  • حافظ على highWaterBytes أقل بشكل معنوي من maxDiskBytes (الافتراضي هو 80%)
  • شغّل openclaw sessions cleanup --dry-run --json بعد تغييرات التكوين للتحقق من التأثير المتوقع قبل التنفيذ
  • للجلسات النشطة المتكررة، مرّر --active-key عند تشغيل التنظيف اليدوي

أمثلة التخصيص

استخدم سياسة تنفيذ محافظة:

{
  session: {
    maintenance: {
      mode: "enforce",
      pruneAfter: "45d",
      maxEntries: 800,
      rotateBytes: "20mb",
      resetArchiveRetention: "14d",
    },
  },
}

تمكين ميزانية قرص صارمة لمجلد الجلسات:

{
  session: {
    maintenance: {
      mode: "enforce",
      maxDiskBytes: "1gb",
      highWaterBytes: "800mb",
    },
  },
}

ضبط للتركيبات الأكبر (مثال):

{
  session: {
    maintenance: {
      mode: "enforce",
      pruneAfter: "14d",
      maxEntries: 2000,
      rotateBytes: "25mb",
      maxDiskBytes: "2gb",
      highWaterBytes: "1.6gb",
    },
  },
}

معاينة أو فرض الصيانة من CLI:

openclaw sessions cleanup --dry-run
openclaw sessions cleanup --enforce

تقليم الجلسات

تقوم OpenClaw بقص نتائج الأدوات القديمة من السياق في الذاكرة مباشرة قبل استدعاءات LLM افتراضياً. هذا لا يعيد كتابة تاريخ JSONL. انظر /concepts/session-pruning.

تفريغ الذاكرة قبل الضغط

عندما تقترب جلسة من الضغط التلقائي، يمكن لـ OpenClaw تشغيل دورة تفريغ ذاكرة صامتة تذكر النموذج بكتابة ملاحظات دائمة على القرص. يعمل هذا فقط عندما تكون مساحة العمل قابلة للكتابة. انظر الذاكرة والضغط.

تعيين وسائط النقل → مفاتيح الجلسات

  • تتبع المحادثات المباشرة session.dmScope (الافتراضي main).
    • main: agent:<agentId>:<mainKey> (استمرارية عبر الأجهزة/القنوات).
      • يمكن لعدة أرقام هواتف وقنوات التعيين إلى نفس المفتاح الرئيسي للوكيل؛ تعمل كوسائط نقل إلى محادثة واحدة.
    • per-peer: agent:<agentId>:dm:<peerId>.
    • per-channel-peer: agent:<agentId>:<channel>:dm:<peerId>.
    • per-account-channel-peer: agent:<agentId>:<channel>:<accountId>:dm:<peerId> (accountId الافتراضي هو default).
    • إذا طابقت session.identityLinks هوية قرين ذات بادئة مزود (على سبيل المثال telegram:123)، فإن المفتاح القياسي يحل محل <peerId> بحيث يشارك نفس الشخص جلسة عبر القنوات.
  • محادثات المجموعة تعزل الحالة: agent:<agentId>:<channel>:group:<id> (الغرف/القنوات تستخدم agent:<agentId>:<channel>:channel:<id>).
    • مواضيع منتدى Telegram تُلحق :topic:<threadId> بمعرف المجموعة للعزل.
    • لا تزال مفاتيح group:<id> القديمة معترف بها للهجرة.
  • قد تستخدم السياقات الواردة group:<id>؛ يتم استنتاج القناة من Provider وتطبيعها إلى الصيغة القياسية agent:<agentId>:<channel>:group:<id>.
  • مصادر أخرى:
    • مهام Cron: cron:<job.id>
    • Webhooks: hook:<uuid> (ما لم يتم ضبطها صراحةً بواسطة الـ hook)
    • عمليات Node: node-<nodeId>

دورة الحياة

  • سياسة إعادة التعيين: يتم إعادة استخدام الجلسات حتى تنتهي صلاحيتها، ويتم تقييم انتهاء الصلاحية عند الرسالة الواردة التالية.
  • إعادة التعيين اليومية: الافتراضي هو الساعة 4:00 صباحاً بالتوقيت المحلي على مضيف البوابة. تصبح الجلسة قديمة بمجرد أن يكون آخر تحديث لها أقدم من وقت إعادة التعيين اليومي الأحدث.
  • إعادة التعيين بسبب الخمول (اختياري): idleMinutes يضيف نافذة خمول منزلقة. عند تكوين كل من إعادة التعيين اليومية وبسبب الخمول، أيهما ينتهي أولاً يجبر على جلسة جديدة.
  • الخمول فقط القديم: إذا قمت بضبط session.idleMinutes دون أي تكوين session.reset/resetByType، تبقى OpenClaw في وضع الخمول فقط للتوافق مع الإصدارات السابقة.
  • تجاوزات حسب النوع (اختياري): resetByType يتيح لك تجاوز السياسة لجلسات direct، و group، و thread (thread = سلاسل Slack/Discord، مواضيع Telegram، سلاسل Matrix عندما يوفرها الموصل).
  • تجاوزات حسب القناة (اختياري): resetByChannel يتجاوز سياسة إعادة التعيين لقناة (ينطبق على جميع أنواع الجلسات لتلك القناة ويأخذ الأولوية على reset/resetByType).
  • محفزات إعادة التعيين: /new أو /reset الدقيقة (بالإضافة إلى أي إضافات في resetTriggers) تبدأ معرف جلسة جديد وتمرر باقي الرسالة. /new <model> يقبل اسم نموذج، أو provider/model، أو اسم مزود (مطابقة تقريبية) لتعيين نموذج الجلسة الجديد. إذا أُرسل /new أو /reset بمفرده، تشغل OpenClaw دورة "ترحيب" قصيرة لتأكيد إعادة التعيين.
  • إعادة التعيين اليدوي: احذف مفاتيح محددة من المخزن أو أزل نص JSONL؛ الرسالة التالية تعيد إنشائها.
  • مهام Cron المعزولة تصنع دائماً sessionId جديد لكل تشغيل (لا إعادة استخدام بسبب الخمول).

سياسة الإرسال (اختياري)

منع التسليم لأنواع جلسات محددة دون سرد معرفات فردية.

{
  session: {
    sendPolicy: {
      rules: [
        { action: "deny", match: { channel: "discord", chatType: "group" } },
        { action: "deny", match: { keyPrefix: "cron:" } },
        // مطابقة مفتاح الجلسة الخام (بما في ذلك البادئة `agent:<id>:`).
        { action: "deny", match: { rawKeyPrefix: "agent:main:discord:" } },
      ],
      default: "allow",
    },
  },
}

تجاوز وقت التشغيل (للمالك فقط):

  • /send on → السماح لهذه الجلسة
  • /send off → الرفض لهذه الجلسة
  • /send inherit → مسح التجاوز واستخدام قواعد التكوين أرسل هذه كرسائل منفردة حتى يتم تسجيلها.

التكوين (مثال إعادة تسمية اختياري)

// ~/.openclaw/openclaw.json
{
  session: {
    scope: "per-sender", // احتفظ بمفاتيح المجموعة منفصلة
    dmScope: "main", // استمرارية الرسائل المباشرة (اضبط per-channel-peer/per-account-channel-peer للصناديق الواردة المشتركة)
    identityLinks: {
      alice: ["telegram:123456789", "discord:987654321012345678"],
    },
    reset: {
      // الافتراضيات: mode=daily, atHour=4 (التوقيت المحلي لمضيف البوابة).
      // إذا قمت أيضاً بضبط idleMinutes، أيهما ينتهي أولاً يفوز.
      mode: "daily",
      atHour: 4,
      idleMinutes: 120,
    },
    resetByType: {
      thread: { mode: "daily", atHour: 4 },
      direct: { mode: "idle", idleMinutes: 240 },
      group: { mode: "idle", idleMinutes: 120 },
    },
    resetByChannel: {
      discord: { mode: "idle", idleMinutes: 10080 },
    },
    resetTriggers: ["/new", "/reset"],
    store: "~/.openclaw/agents/{agentId}/sessions/sessions.json",
    mainKey: "main",
  },
}

الفحص

  • openclaw status — يظهر مسار المخزن والجلسات الحديثة.
  • openclaw sessions --json — يفرغ كل إدخال (فلترة باستخدام --active <minutes>).
  • openclaw gateway call sessions.list --params '{}' — جلب الجلسات من البوابة قيد التشغيل (استخدم --url/--token للوصول إلى البوابة البعيدة).
  • أرسل /status كرسالة منفردة في الدردشة لمعرفة ما إذا كان الوكيل يمكن الوصول إليه، وكم من سياق الجلسة مستخدم، وتبديلات التفكير/التفصيل الحالية، ومتى تم تحديث بيانات اعتماد WhatsApp web الخاصة بك آخر مرة (يساعد في اكتشاف احتياجات إعادة الربط).
  • أرسل /context list أو /context detail لرؤية ما في موجه النظام وملفات مساحة العمل المحقونة (وأكبر المساهمين في السياق).
  • أرسل /stop (أو عبارات إلغاء منفردة مثل stop, stop action, stop run, stop openclaw) لإلغاء التشغيل الحالي، ومسح المتابعات في قائمة الانتظار لتلك الجلسة، وإيقاف أي تشغيلات وكيل فرعي ناتجة منها (يشمل الرد عدد ما تم إيقافه).
  • أرسل /compact (تعليمات اختيارية) كرسالة منفردة لتلخيص السياق الأقدم وتحرير مساحة النافذة. انظر /concepts/compaction.
  • يمكن فتح نصوص JSONL مباشرة لمراجعة الدورات الكاملة.

نصائح

  • احتفظ بالمفتاح الأساسي مخصصاً لحركة المرور من واحد لواحد؛ دع المجموعات تحتفظ بمفاتيحها الخاصة.
  • عند أتمتة التنظيف، احذف مفاتيح فردية بدلاً من المخزن بالكامل للحفاظ على السياق في أماكن أخرى.

بيانات وصفية لأصل الجلسة

يسجل كل إدخال جلسة من أين أتى (بأفضل جهد) في origin:

  • label: تسمية بشرية (تم حلها من تسمية المحادثة + موضوع/قناة المجموعة)
  • provider: معرف قناة موحد (بما في ذلك الامتدادات)
  • from/to: معرفات التوجيه الخام من المغلف الوارد
  • accountId: معرف حساب المزود (عند تعدد الحسابات)
  • threadId: معرف سلسلة/موضوع عندما تدعم القناة ذلك يتم تعبئة حقول الأصل للرسائل المباشرة والقنوات والمجموعات. إذا قام الموصل بتحديث توجيه التسليم فقط (على سبيل المثال، للحفاظ على جلسة الرسائل المباشرة الرئيسية جديدة)، فيجب أن يزال يوفر سياقاً وارداً حتى تحتفظ الجلسة ببياناتها التوضيحية. يمكن للامتدادات القيام بذلك عن طريق إرسال ConversationLabel, GroupSubject, GroupChannel, GroupSpace, و SenderName في السياق الوارد واستدعاء recordSessionMetaFromInbound (أو تمرير نفس السياق إلى updateLastRoute).

التهيئةتقليم الجلسات