Technical reference

نظرة متعمقة على إدارة الجلسات

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

ابدأ بوثائق النظرة العامة: إدارة الجلسات، وCompaction، ونظرة عامة على الذاكرة، والبحث في الذاكرة، وتنقيح الجلسات، وسلامة السجل النصي، ومرجع الإعداد الكامل في إعداد الوكيل.

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

  1. صفوف الجلسات (SQLite لكل وكيل) - خريطة مفاتيح/قيم sessionKey -> SessionEntry. حالة تشغيل قابلة للتغيير يملكها Gateway. تتعقب البيانات الوصفية: معرّف الجلسة الحالي، وآخر نشاط، وخيارات التبديل، وعدادات الرموز.
  2. أحداث السجل النصي (SQLite لكل وكيل) - للإلحاق فقط، ومنظمة على هيئة شجرة (تحتوي الإدخالات على id + parentId). تخزن المحادثة واستدعاءات الأدوات وملخصات Compaction؛ وتعيد بناء سياق النموذج للمنعطفات المستقبلية. نقاط تحقق Compaction هي بيانات وصفية فوق السجل النصي اللاحق الذي خضع للضغط - ولا تكتب عملية Compaction جديدة نسخة .checkpoint.*.jsonl ثانية.

قد تظل عمليات التثبيت القديمة تحتوي على ملفات sessions.json ضمن دليل الوكيل sessions/. تعامل مع هذه الملفات على أنها مدخلات لترحيل صفوف الجلسات القديمة أو أهداف صيانة صريحة دون اتصال. يستورد بدء تشغيل Gateway وopenclaw doctor --fix الصفوف القديمة النشطة وسجل السجلات النصية إلى مخزن SQLite الخاص بكل وكيل تلقائيًا. شغّل openclaw doctor --session-sqlite inspect --session-sqlite-all-agents، ثم اتبع تسلسل ترحيل Doctor ، عندما تحتاج إلى دليل صريح للفحص أو التحقق. إذا فشل ترحيل بعد أرشفة عناصر السجل النصي القديمة، فاستخدم وضع استرداد Doctor من ذلك التسلسل. يستخدم الاسترداد بيانات توصيف الترحيل، ويستعيد فقط عناصر الدعم المؤرشفة المتأثرة، ويُعد تقرير مشكلة منقحًا على GitHub عند طلبه، ولا يجعل وقت التشغيل النشط يقرأ ملفات JSONL مجددًا.

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

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

لكل وكيل، على مضيف Gateway (يُحل عبر src/config/sessions.ts):

  • مخزن صفوف جلسات وقت التشغيل: ~/.openclaw/agents/<agentId>/agent/openclaw-agent.sqlite
  • صفوف سجلات وقت التشغيل النصية: ~/.openclaw/agents/<agentId>/agent/openclaw-agent.sqlite
  • عناصر السجلات النصية القديمة/المؤرشفة: ~/.openclaw/agents/<agentId>/sessions/
  • مدخل ترحيل الصفوف القديمة: ~/.openclaw/agents/<agentId>/sessions/sessions.json

صيانة المخزن وضوابط القرص

يتحكم session.maintenance في الصيانة التلقائية لصفوف جلسات SQLite، وصفوف سجلات SQLite النصية، وعناصر الأرشيف، والملفات الجانبية للمسارات:

المفتاح الافتراضي ملاحظات
mode "enforce" أو "warn" (إبلاغ فقط، دون تعديل)
pruneAfter "30d" حد عمر الإدخالات القديمة
maxEntries 500 الحد الأقصى لإدخالات الجلسات
resetArchiveRetention الاحتفاظ (دون حد للعمر) حد عمر أرشيفات السجل النصي *.reset.*/*.deleted.*؛ وتؤدي مدة محددة إلى تفعيل الحذف
maxDiskBytes 2gb ميزانية قرص الجلسات لكل وكيل؛ يعطّلها false
highWaterBytes 80% من maxDiskBytes الهدف بعد تنظيف الميزانية

يُحتفظ بالسجلات النصية المؤرشفة افتراضيًا وتُضغط باستخدام zstd (*.jsonl.<reason>.<timestamp>.zst) عندما يدعم وقت التشغيل ذلك، بحيث لا يؤدي حذف جلسة أو إعادة تعيينها إلى التخلص بصمت من سجل المحادثة. تُخرج ميزانية القرص أقدم الأرشيفات أولًا، قبل المساس بالجلسات النشطة.

يقيس الإنفاذ النشط لـ maxDiskBytes في SQLite بايتات JSON لصف الجلسة إضافة إلى بايتات JSON لأحداث السجل النصي لكل جلسة؛ بينما يقيس إنفاذ الصيانة القديمة دون اتصال الملفات الموجودة في دليل الجلسات المحدد.

تحصل جلسات فحص تشغيل نموذج Gateway (المفاتيح المطابقة لـ agent:*:explicit:model-run-<uuid>) على مدة احتفاظ ثابتة ومنفصلة 24h. يخضع هذا التنقيح لضغط السعة: فلا يعمل إلا عند بلوغ ضغط صيانة/حد إدخالات الجلسات، وفقط قبل خطوة التنظيف/الحد العامة للإدخالات القديمة. لا تستخدم الجلسات الصريحة الأخرى مدة الاحتفاظ هذه.

ترتيب الإنفاذ لتنظيف ميزانية القرص (mode: "enforce"):

  1. أزل أولًا أقدم عناصر السجل النصي المؤرشفة، أو العناصر القديمة اليتيمة، أو عناصر المسارات اليتيمة.
  2. إذا ظل الاستخدام أعلى من الهدف، فأخرج أقدم إدخالات الجلسات وصفوف سجلاتها النصية أو عناصر مساراتها.
  3. كرر حتى يصبح الاستخدام مساويًا لـ highWaterBytes أو أقل منه.

يبلغ mode: "warn" عن عمليات الإخراج المحتملة دون تعديل المخزن أو الملفات.

شغّل الصيانة عند الطلب:

bash
openclaw sessions cleanup --dry-runopenclaw sessions cleanup --enforce

تحافظ الصيانة على مؤشرات المحادثات الخارجية الدائمة مثل جلسات المجموعات وجلسات الدردشة ذات نطاق سلاسل المحادثة، لكن يمكن مع ذلك إزالة إدخالات وقت التشغيل الاصطناعية (cron، والخطافات، وHeartbeat، وACP، والوكلاء الفرعيين) بعد تجاوزها العمر أو العدد أو ميزانية القرص المضبوطة. تستخدم عمليات cron المعزولة عنصر تحكم منفصلًا cron.sessionRetention، مستقلًا عن مدة الاحتفاظ بفحوص تشغيل النموذج.

تمر كتابات Gateway العادية عبر موصل الجلسات، الذي يسلسل تعديلات SQLite لكل وكيل عبر مسار كاتب وقت التشغيل. ينبغي أن تفضل شيفرة وقت التشغيل مساعدات الموصل في src/config/sessions/session-accessor.ts؛ أما مساعدات sessions.json القديمة فهي أدوات للترحيل والصيانة دون اتصال. عندما يكون Gateway قابلًا للوصول، تفوض عمليتا openclaw sessions cleanup وopenclaw agents delete غير التجريبيتين تعديلات المخزن إلى Gateway لكي ينضم التنظيف إلى قائمة انتظار الكاتب نفسها؛ ويمثل --store <path> مسار الإصلاح الصريح دون اتصال لمخزن قديم محدد، ويظل محليًا دائمًا (وكذلك --dry-run). يُنفذ تنظيف maxEntries على دفعات للمخازن ذات الحجم الإنتاجي، لذلك قد يتجاوز المخزن الحد المضبوط لفترة وجيزة قبل أن تعيد عملية تنظيف مستوى الامتلاء المرتفع التالية كتابته إلى ما دون الحد. لا تنقّح عمليات القراءة الإدخالات ولا تفرض حدًا عليها أثناء بدء تشغيل Gateway - لا تفعل ذلك إلا عمليات الكتابة أو openclaw sessions cleanup --enforce، كما يطبق الأخير الحد فورًا وينقّح عناصر السجل النصي ونقاط التحقق والمسارات القديمة غير المُشار إليها حتى مع عدم ضبط ميزانية للقرص.

لم يعد OpenClaw ينشئ نسخ تدوير احتياطية تلقائية sessions.json.bak.* أثناء كتابات Gateway. يرفض المخطط الحالي المفتاح القديم session.maintenance.rotateBytes، ويزيله openclaw doctor --fix من الإعدادات القديمة.

تستخدم تعديلات السجل النصي قائمة انتظار كتابة الجلسة لهدف سجل SQLite النصي:

الإعداد الافتراضي تجاوز متغير البيئة
session.writeLock.acquireTimeoutMs 60000 OPENCLAW_SESSION_WRITE_LOCK_ACQUIRE_TIMEOUT_MS
session.writeLock.staleMs 1800000 OPENCLAW_SESSION_WRITE_LOCK_STALE_MS
session.writeLock.maxHoldMs 300000 OPENCLAW_SESSION_WRITE_LOCK_MAX_HOLD_MS

يمثل acquireTimeoutMs المدة التي ينتظرها القفل قبل إظهار خطأ انشغال الجلسة والاستسلام؛ ولا تزده إلا عندما تتنافس عمليات التحضير أو التنظيف أو Compaction أو عكس السجل النصي المشروعة لمدة أطول على الأجهزة البطيئة. يحدد staleMs متى يمكن استرداد قفل موجود باعتباره قديمًا. يمثل maxHoldMs حد تحرير المراقب داخل العملية.

الرجوع إلى إصدار أقدم بعد الانتقال إلى SQLite

استعد عناصر السجل النصي القديمة المؤرشفة قبل تشغيل إصدار أقدم من OpenClaw يعتمد على الملفات:

bash
openclaw doctor --session-sqlite restore --session-sqlite-all-agents

يترك الترحيل ملفات sessions.json القديمة في مكانها لأغراض الدعم والتراجع، لكن ملفات JSONL النشطة للسجل النصي التي استوردت إلى SQLite تُعاد تسميتها إلى session-sqlite-import-archive/. تتبع أوقات التشغيل الأقدم المعتمدة على الملفات مسارات sessionFile في sessions.json، ولذلك تحتاج إلى استعادة هذه العناصر قبل بدء التشغيل. تستخدم الاستعادة بيانات توصيف الترحيل، وتنقل فقط العناصر المؤرشفة المسجلة التي تكون مساراتها الأصلية مفقودة، وتترك قاعدة بيانات SQLite في مكانها للاسترداد اللاحق.

الجلسات المنشأة بعد الانتقال إلى SQLite موجودة في SQLite فقط ولن تظهر لوقت تشغيل أقدم يعتمد على الملفات. إذا أجريت ترقية مجددًا بعد الرجوع إلى إصدار أقدم، فشغّل تسلسل فحص Doctor والتحقق مجددًا حتى يتمكن OpenClaw من التحقق من العناصر القديمة المستعادة قبل استيرادها.

جلسات Cron وسجلات التشغيل

تنشئ عمليات cron المعزولة إدخالات جلسات/سجلات نصية خاصة بها مع مدة احتفاظ مخصصة:

  • ينقّح cron.sessionRetention (الافتراضي "24h") جلسات تشغيل cron المعزولة القديمة من المخزن؛ ويعطّله false.
  • يحتفظ سجل التشغيل بأحدث 2000 صف نهائي لكل مهمة cron. تحتفظ الصفوف المفقودة بنافذة التنظيف البالغة 24 ساعة.

عندما ينشئ cron جلسة تشغيل معزولة جديدة قسرًا، فإنه ينقح إدخال الجلسة السابق cron:<jobId> قبل كتابة الصف الجديد: فهو ينقل التفضيلات الآمنة (إعدادات التفكير/السرعة/الإسهاب/الاستدلال، والتسميات، واسم العرض) وتجاوزات النموذج/المصادقة التي حددها المستخدم صراحة، لكنه يسقط سياق المحادثة المحيط (توجيه القناة/المجموعة، وسياسة الإرسال/قائمة الانتظار، ورفع الصلاحيات، والأصل، وارتباط وقت تشغيل ACP) حتى لا يرث تشغيل معزول جديد صلاحية تسليم أو وقت تشغيل قديمة من تشغيل أقدم.

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

يحدد sessionKey حاوية المحادثة التي توجد فيها (التوجيه + العزل). القواعد المعيارية: /concepts/session.

النمط المثال
الدردشة الرئيسية/المباشرة (لكل وكيل) 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> (ما لم يتم تجاوزه)

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

يشير كل sessionKey إلى sessionId حالي (هوية سجل SQLite النصي التي تواصل المحادثة). يوجد منطق القرار في initSessionState() ضمن src/auto-reply/reply/session.ts.

  • إعادة الضبط (/new، /reset) تنشئ sessionId جديدة لذلك sessionKey.
  • إعادة الضبط اليومية (الافتراضي الساعة 4:00 صباحًا بالتوقيت المحلي على مضيف Gateway) تنشئ sessionId جديدة عند أول رسالة بعد حد إعادة الضبط.
  • انتهاء الصلاحية بسبب الخمول (session.reset.idleMinutes، أو session.idleMinutes القديم) ينشئ sessionId جديدة عند وصول رسالة بعد نافذة الخمول. إذا جرى إعداد كلٍّ من الإعداد اليومي وإعداد الخمول، فتكون الأولوية لما تنتهي صلاحيته أولًا.
  • استئناف إعادة اتصال واجهة التحكم يحافظ على الجلسة الظاهرة حاليًا لعملية إرسال واحدة بعد إعادة الاتصال عندما يتلقى Gateway قيمة sessionId المطابقة من عميل واجهة مستخدم للمشغّل. هذه إشارة لمرة واحدة؛ أما عمليات الإرسال القديمة العادية فلا تزال تنشئ sessionId جديدة.
  • أحداث النظام (Heartbeat، وتنبيهات Cron، وإشعارات exec، ومسك دفاتر Gateway) قد تعدّل صف الجلسة، لكنها لا تمدّد مطلقًا حداثة إعادة الضبط اليومية أو الناتجة عن الخمول. يتخلص الانتقال عند إعادة الضبط من إشعارات أحداث النظام الموضوعة في قائمة الانتظار للجلسة السابقة قبل إنشاء الموجّه الجديد.
  • سياسة تفريع الأصل تستخدم الفرع النشط في OpenClaw عند إنشاء تفريع لسلسلة محادثة أو لوكيل فرعي. إذا كان ذلك الفرع كبيرًا جدًا (أكثر من حد داخلي ثابت، يبلغ حاليًا 100K رمز)، يبدأ OpenClaw الفرع الابن بسياق معزول بدلًا من الفشل أو وراثة سجل غير قابل للاستخدام. يُحدَّد الحجم تلقائيًا ولا يمكن إعداده؛ ويزيل openclaw doctor --fix إعداد session.parentForkMaxTokens القديم.
  • تفريعات المشغّل: ينشئ sessions.create { parentSessionKey, fork: true } جلسة جديدة يتفرع نصها من الحالة الحالية للجلسة الأصلية (باستخدام آلية التفريع نفسها المستخدمة عند إنشاء الوكلاء الفرعيين، بما في ذلك حد الحجم أعلاه). يُرفض التفريع أثناء وجود تشغيل نشط في الجلسة الأصلية، ويرث اختيار النموذج منها ما لم يُمرَّر نموذج صراحةً، ويضع علامة forkedFromParent على الجلسة الابنة مع عدادات رموز جديدة.

مخطط مخزن الجلسات

يحتفظ مخزن وقت التشغيل بقيم SessionEntry في SQLite خاص بكل وكيل. نوع القيمة هو SessionEntry في src/config/sessions.ts. الحقول الأساسية (القائمة غير شاملة):

  • sessionId: معرّف النص الحالي المستخدم لمخاطبة صفوف النص في SQLite
  • sessionStartedAt: الطابع الزمني لبدء sessionId الحالية؛ تعتمد عليه حداثة إعادة الضبط اليومية. قد تستمد الصفوف القديمة هذه القيمة من ترويسة جلسة JSONL.
  • lastInteractionAt: الطابع الزمني لآخر تفاعل حقيقي للمستخدم أو القناة؛ تعتمد عليه حداثة إعادة الضبط بسبب الخمول، كي لا تُبقي أحداث Heartbeat وCron وexec الجلسات نشطة. تعود الصفوف القديمة التي لا تحتوي هذا الحقل إلى وقت بدء الجلسة المستعاد.
  • updatedAt: الطابع الزمني لآخر تعديل لصف المخزن، ويُستخدم للإدراج والتنقية ومسك الدفاتر، وليس المرجع المعتمد لحداثة إعادة الضبط اليومية أو بسبب الخمول.
  • archivedAt: طابع زمني اختياري للأرشفة. تبقى الجلسات المؤرشفة في المخزن ونصوصها سليمة، وتُستبعد من قوائم الجلسات النشطة العادية.
  • pinnedAt: طابع زمني اختياري للتثبيت. تُرتَّب الجلسات النشطة المثبتة قبل الجلسات غير المثبتة؛ وتؤدي أرشفة جلسة إلى إلغاء تثبيتها.
  • التشغيل البيني مع سلاسل Codex: يتبع كلا الحقلين بنية إدارة السلاسل في Codex؛ إذ تُشتق القيمتان المنطقيتان archived/pinned المنقولتان عبر الاتصال دائمًا من الطابع الزمني وتُسجّلان على جانب الخادم، بما يطابق دلالات threads.archived_at في Codex وتسلسل camelCase. تستخدم طوابع OpenClaw الزمنية أجزاء الألف من الثانية منذ الحقبة، بينما يستخدم Codex الثواني منذ الحقبة، لذا تُجري الجسور التحويل عند حد Plugin الخاص بـ codex. لا يوفّر Codex واجهة API للتثبيت بعد (thread/archive/thread/unarchive فقط)؛ لذلك تبقى حالة التثبيت في جانب OpenClaw حتى تتوفر واجهة كهذه، وعندها تتيح البنية المطابقة للجلسات المرتبطة إجراء رحلة ذهاب وإياب لحالة التثبيت آليًا.
  • لا تعرض مراقبة Codex إلا السلاسل الأصلية غير المؤرشفة. لا يمكن أرشفة سلسلة idle محلية في Gateway أو سلسلة notLoaded ذات نشاط مجهول عبر thread/archive الأصلي إلا بعد أن يؤكد المشغّل صراحةً عدم امتلاك أي عملية Codex أخرى لها؛ ويُجري Plugin أولًا قراءة جديدة للحالة المحلية للعملية، ثم تختفي السلسلة من الكتالوج. لا يمكن لتلك القراءة إثبات أن عملية App Server أخرى لا تستخدم السلسلة. يرفض OpenClaw أرشفة الصفوف النشطة وصفوف الأخطاء، ولا تتوفر أرشفة العقدة المقترنة حتى يتمكن جسر العقدة من امتلاك دورة حياة السلسلة المتدفقة بالكامل. تؤدي إزالة الأرشفة في عميل Codex أصلي إلى جعل السلسلة مؤهلة للظهور مجددًا.
  • lastReadAt / markedUnreadAt: طوابع زمنية لحالة القراءة يسجلها sessions.patch { unread } على جانب الخادم؛ يسجل unread: false عملية قراءة (يضبط lastReadAt ويمسح markedUnreadAt)؛ ويضع unread: true علامة غير مقروءة على الجلسة حتى القراءة التالية. تعرض صفوف الجلسات قيمة منطقية مشتقة باسم unread: إما أنها محددة صراحةً كغير مقروءة، أو أن قراءتها سبقت أحدث نشاط. تبقى الجلسات التي لم تُحدَّد كمقروءة قط unread: false، حتى لا تظهر مؤشرات جديدة في عمليات التثبيت الحالية عند الترقية.
  • lastActivityAt: الطابع الزمني لآخر تشغيل مكتمل للوكيل يُحتسب نشاطًا يستحق وضع علامة غير مقروء (تشغيلات المستخدم والقناة وCron). لا تحدّثه دورات Heartbeat والأحداث الداخلية ولا تصحيحات البيانات الوصفية؛ ولا تُعد updatedAt إشارة نشاط.
  • sessionFile: علامة قديمة محتفظ بها للتوافق مع الترحيل والأرشفة؛ يستخدم وقت التشغيل النشط هوية SQLite
  • chatType: direct | group | room
  • provider، subject، room، space، displayName: بيانات وصفية لتسمية المجموعة أو القناة
  • خيارات التبديل: thinkingLevel، verboseLevel، reasoningLevel، elevatedLevel، sendPolicy (تجاوز خاص بكل جلسة)
  • اختيار النموذج: providerOverride، modelOverride، authProfileOverride
  • عدادات الرموز (وفق أفضل تقدير وتعتمد على المزوّد): inputTokens، outputTokens، totalTokens، contextTokens
  • compactionCount: عدد مرات اكتمال Compaction التلقائي لمفتاح الجلسة هذا
  • memoryFlushAt / memoryFlushCompactionCount: الطابع الزمني وعدد عمليات Compaction لآخر تفريغ للذاكرة قبل Compaction

Gateway هو المرجع المعتمد: وقد يعيد كتابة الإدخالات أو تعبئتها أثناء تشغيل الجلسات. بالنسبة إلى عمليات التثبيت القديمة المعتمدة على الملفات، رحّل باستخدام openclaw doctor --session-sqlite import --session-sqlite-all-agents بدلًا من تعديل sessions.json وتوقّع استمرار وقت التشغيل في قراءة ذلك الملف.

بنية أحداث النص

يدير موصّل جلسات OpenClaw النصوص ويعرضها لرمز وقت التشغيل عبر أدوات مساعدة قائمة على الهوية. تدفق الأحداث للإلحاق فقط:

  • الإدخال الأول: ترويسة الجلسة - type: "session"، id، cwd، timestamp، وparentSession اختياري.
  • ثم: إدخالات تحتوي id + parentId (بنية شجرية).

أنواع الإدخالات الجديرة بالملاحظة:

  • message: رسائل المستخدم والمساعد وtoolResult
  • custom_message: رسالة يحقنها الامتداد وتدخل بالفعل في سياق النموذج (تُعرض في TUI عندما تكون display: true، وتُخفى بالكامل عندما تكون display: false)
  • custom: حالة امتداد لا تدخل في سياق النموذج (لاستمرار حالة الامتداد عبر عمليات إعادة التحميل)
  • compaction: ملخص Compaction مستمر يحتوي firstKeptEntryId وtokensBefore
  • branch_summary: ملخص مستمر عند التنقل في فرع شجري

لا يُجري OpenClaw عمدًا «تصحيحًا» للنصوص؛ إذ يستخدم Gateway ‏SessionManager لقراءتها وكتابتها.

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

مفهومان مختلفان:

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

المزيد عن الحدود: /reference/token-use.

Compaction: ماهيته

يلخّص Compaction المحادثة الأقدم في إدخال compaction مستمر ضمن النص، مع إبقاء الرسائل الحديثة سليمة. بعد Compaction، ترى الدورات اللاحقة ملخص Compaction إضافةً إلى الرسائل اللاحقة لـ firstKeptEntryId. يُعد Compaction مستمرًا، بخلاف تنقية الجلسة؛ راجع /concepts/session-pruning.

تكون إعادة حقن قسم AGENTS.md بعد Compaction اختيارية عبر agents.defaults.compaction.postCompactionSections؛ وعندما تكون غير مضبوطة أو تكون []، لا يضيف OpenClaw مقتطفات AGENTS.md فوق ملخص Compaction.

حدود الأجزاء واقتران الأدوات

عند تقسيم نص طويل إلى أجزاء Compaction، يُبقي OpenClaw استدعاءات أدوات المساعد مقترنة بإدخالات toolResult المطابقة لها:

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

متى يحدث Compaction التلقائي

مشغّلان في وكيل OpenClaw المضمّن:

  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، ومتغيرات أخرى وفق بنية المزوّد)؛ يُجرى Compaction ثم تُعاد المحاولة. عندما يبلّغ المزوّد عن عدد الرموز التي جرت محاولة استخدامها، يمرر OpenClaw ذلك العدد المرصود إلى Compaction الخاص بالاسترداد من التجاوز؛ وإذا أكد المزوّد حدوث التجاوز لكنه لم يعرض عددًا قابلًا للتحليل، يمرر OpenClaw عددًا اصطناعيًا يتجاوز الميزانية بالحد الأدنى إلى محركات Compaction وأدوات التشخيص. إذا ظل الاسترداد من التجاوز يفشل، يعرض OpenClaw إرشادات صريحة ويحافظ على تعيين الجلسة الحالي بدلًا من الانتقال بصمت إلى معرّف جلسة جديد؛ أعد محاولة إرسال الرسالة، أو شغّل /compact، أو شغّل /new.
  2. صيانة الحد: بعد دورة ناجحة، عندما contextTokens > contextWindow - reserveTokens، حيث تمثل contextWindow نافذة سياق النموذج وتمثل reserveTokens هامشًا محجوزًا للموجّهات إضافةً إلى إخراج النموذج التالي.

يعمل حارسان إضافيان خارج هذين المشغّلين:

  • Compaction المحلي السابق للتشغيل: اضبط agents.defaults.compaction.maxActiveTranscriptBytes (بوحدات البايت أو كسلسلة مثل "20mb") لتشغيل Compaction محلي قبل فتح التشغيل التالي بمجرد بلوغ النص النشط ذلك الحجم. هذا حارس حجم لتكلفة إعادة الفتح المحلية، وليس أرشفة خامًا؛ إذ يظل Compaction الدلالي العادي يعمل، ويتطلب truncateAfterCompaction حتى يصبح الملخص المضغوط نصًا لاحقًا جديدًا.
  • الفحص المسبق في منتصف الدورة: اضبط agents.defaults.compaction.midTurnPrecheck.enabled: true (القيمة الافتراضية false) لإضافة حارس لحلقة الأدوات. بعد إلحاق نتيجة أداة وقبل استدعاء النموذج التالي، يقدّر OpenClaw ضغط الموجّه باستخدام منطق ميزانية الفحص السابق للتشغيل نفسه المستخدم عند بدء الدورة. إذا لم يعد السياق ملائمًا، فلا ينفّذ الحارس Compaction ضمنيًا؛ بل يطلق إشارة فحص مسبق منظّمة في منتصف الدورة، ويوقف إرسال الموجّه الحالي، ويتيح لحلقة التشغيل الخارجية استخدام مسار الاسترداد الحالي (اقتطاع نتائج الأدوات كبيرة الحجم عندما يكون ذلك كافيًا، أو تشغيل وضع Compaction المُعدّ وإعادة المحاولة). يعمل مع وضعي Compaction ‏default وsafeguard، بما في ذلك Compaction الوقائي المدعوم من المزوّد. وهو مستقل عن maxActiveTranscriptBytes: يعمل حارس الحجم بالبايت قبل فتح الدورة، بينما يعمل الفحص المسبق في منتصف الدورة لاحقًا، بعد إلحاق نتائج أدوات جديدة.

إعدادات Compaction

json5
{  agents: {    defaults: {      compaction: {        enabled: true,        reserveTokens: 16384,        keepRecentTokens: 20000,      },    },  },}

يفرض OpenClaw أيضًا حدًا أدنى للسلامة لعمليات التشغيل المضمّنة: إذا كانت compaction.reserveTokens أقل من reserveTokensFloor (القيمة الافتراضية 20000)، يرفعها OpenClaw إلى ذلك الحد. اضبط agents.defaults.compaction.reserveTokensFloor: 0 لتعطيل الحد الأدنى. عندما تكون نافذة سياق النموذج النشط معروفة، يُقيَّد كل من الحد الأدنى والاحتياطي الفعلي النهائي بحيث لا يمكن للاحتياطي استهلاك ميزانية الموجّه بالكامل. يمنع هذا النماذج ذات السياق الصغير (مثل نموذج محلي بسعة 16K رمز) من الدخول في Compaction منذ الرمز الأول؛ ومن دون نافذة سياق معروفة، تظل ميزانيات الاحتياطي المضبوطة والحالية غير مقيّدة. سبب وجود حد أدنى أصلًا: ترك هامش كافٍ لمهام «الصيانة» متعددة الأدوار (مثل تفريغ الذاكرة الموضح أدناه) قبل أن يصبح Compaction حتميًا. التنفيذ: applyAgentCompactionSettingsFromConfig() في src/agents/agent-settings.ts، ويُستدعى من مسارات إعداد دور المشغّل المضمّن وCompaction.

يحترم /compact اليدوي قيمة agents.defaults.compaction.keepRecentTokens الصريحة ويحافظ على نقطة اقتطاع الذيل الحديث الخاصة ببيئة التشغيل. من دون ميزانية احتفاظ صريحة، يكون Compaction اليدوي نقطة تحقق صارمة، ويبدأ السياق المعاد بناؤه من الملخص الجديد.

عند تمكين truncateAfterCompaction، يدوّر OpenClaw النسخة النصية النشطة إلى نسخة لاحقة خضعت لـCompaction بعد اكتماله. تستخدم إجراءات نقاط تحقق التفرع/الاستعادة تلك النسخة اللاحقة؛ وتظل ملفات نقاط التحقق القديمة السابقة لـCompaction قابلة للقراءة ما دامت مُشارًا إليها.

موفّرو Compaction القابلون للتوصيل

تسجّل Plugins موفّر Compaction عبر registerCompactionProvider() في واجهة API الخاصة بالـPlugin. عندما تُضبط agents.defaults.compaction.provider على معرّف موفّر مسجّل، يفوّض امتداد الحماية التلخيص إلى ذلك الموفّر بدلًا من مسار summarizeInStages المدمج.

  • provider: معرّف Plugin مسجّل لموفّر Compaction. اتركه من دون ضبط لاستخدام تلخيص LLM الافتراضي. يؤدي ضبط provider إلى فرض mode: "safeguard".
  • يتلقى الموفّرون تعليمات Compaction وسياسة الحفاظ على المعرّفات نفسها التي يتلقاها المسار المدمج، وتظل آلية الحماية تحافظ على سياق لاحقة الأدوار الحديثة والأدوار المجزأة بعد مخرجات الموفّر.
  • يعيد تلخيص الحماية المدمج استخلاص الملخصات السابقة مع الرسائل الجديدة بدلًا من الاحتفاظ بالملخص السابق كاملًا كما هو.
  • يمكّن وضع الحماية تدقيقات جودة الملخص افتراضيًا؛ اضبط qualityGuard.enabled: false لتخطي سلوك إعادة المحاولة عند وجود مخرجات مشوّهة.
  • إذا فشل الموفّر أو أعاد نتيجة فارغة، يعود OpenClaw تلقائيًا إلى تلخيص LLM المدمج. تُعاد إشارات الإلغاء/انتهاء المهلة التي شغّلها المستدعي صراحةً بدلًا من ابتلاعها، بحيث يُحترم الإلغاء دائمًا.

المصدر: src/plugins/compaction-provider.ts، src/agents/agent-hooks/compaction-safeguard.ts.

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

  • /status في أي جلسة محادثة
  • openclaw status ‏(CLI)
  • openclaw sessions / openclaw sessions --json
  • سجلات Gateway ‏(pnpm gateway:watch أو openclaw logs --follow): ‏embedded run auto-compaction start + complete
  • الوضع التفصيلي: 🧹 Auto-compaction complete بالإضافة إلى عدد عمليات Compaction

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

يدعم OpenClaw أدوارًا «صامتة» لمهام الخلفية التي ينبغي ألا يرى المستخدم مخرجاتها الوسيطة.

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

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

قبل حدوث Compaction التلقائي، يمكن لـOpenClaw تشغيل دور وكيلي صامت يكتب حالة دائمة على القرص (مثل memory/YYYY-MM-DD.md في مساحة عمل الوكيل) كي لا يتمكن Compaction من محو السياق الحرج. يراقب استخدام سياق الجلسة، وبمجرد تجاوزه عتبة مرنة أدنى من عتبة Compaction، يرسل توجيهًا صامتًا «اكتب الذاكرة الآن» باستخدام رمز الصمت الدقيق NO_REPLY / no_reply بحيث لا يرى المستخدم شيئًا.

الإعداد (agents.defaults.compaction.memoryFlush)، والمرجع الكامل في /gateway/config-agents:

المفتاح القيمة الافتراضية ملاحظات
enabled true
model غير مضبوط تجاوز دقيق للموفّر/النموذج لدور التفريغ فقط، مثل ollama/qwen3:8b
softThresholdTokens 4000 الفجوة الواقعة دون عتبة Compaction التي تشغّل عملية التفريغ
forceFlushTranscriptBytes غير مضبوط (معطّل) يفرض عملية تفريغ بمجرد بلوغ ملف النسخة النصية حجم البايتات هذا (أو سلسلة مثل "2mb")، حتى إذا كانت عدادات الرموز قديمة؛ وتؤدي 0 إلى التعطيل
prompt مدمج رسالة المستخدم لدور التفريغ
systemPrompt مدمج موجّه نظام إضافي يُلحق بدور التفريغ

ملاحظات:

  • يتضمن الموجّه/موجّه النظام الافتراضي تلميح NO_REPLY لمنع التسليم.
  • عند ضبط model، يستخدم دور التفريغ ذلك النموذج من دون وراثة سلسلة الاحتياط للجلسة النشطة، بحيث لا تعود صيانة محلية فقط بصمت إلى نموذج محادثة مدفوع عند الفشل.
  • يعمل التفريغ مرة واحدة لكل دورة Compaction (ويُتتبّع ذلك في صف الجلسة).
  • يعمل التفريغ فقط لجلسات OpenClaw المضمّنة؛ وتتخطاه خلفيات CLI وأدوار Heartbeat.
  • يُتخطى التفريغ عندما تكون مساحة عمل الجلسة للقراءة فقط (workspaceAccess: "ro" أو "none").
  • راجع الذاكرة لمعرفة تخطيط ملفات مساحة العمل وأنماط الكتابة.

يعرض OpenClaw خطاف session_before_compact في واجهة API الخاصة بالامتدادات، لكن منطق التفريغ أعلاه يوجد في جانب Gateway ‏(src/auto-reply/reply/memory-flush.ts، ‏src/auto-reply/reply/agent-runner-memory.ts) وليس في ذلك الخطاف.

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

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

ذو صلة

Was this useful?
On this page

On this page