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

أدوات الجلسات

الهدف: مجموعة أدوات صغيرة يصعب إساءة استخدامها حتى يتمكن الوكلاء من سرد الجلسات، واسترجاع السجل، والإرسال إلى جلسة أخرى.

أسماء الأدوات

  • sessions_list
  • sessions_history
  • sessions_send
  • sessions_spawn

النموذج الرئيسي

  • دلو الدردشة المباشر الرئيسي هو دائمًا المفتاح الحرفي "main" (يتم حله إلى المفتاح الرئيسي للوكيل الحالي).
  • الدردشات الجماعية تستخدم agent:<agentId>:<channel>:group:<id> أو agent:<agentId>:<channel>:channel:<id> (تمرير المفتاح الكامل).
  • الوظائف المجدولة تستخدم cron:<job.id>.
  • الخطافات تستخدم hook:<uuid> ما لم يتم تعيينها صراحةً.
  • جلسات العقدة تستخدم node-<nodeId> ما لم يتم تعيينها صراحةً.

القيم global و unknown محجوزة ولا يتم سردها أبدًا. إذا كان session.scope = "global"، فإننا نستخدم الاسم المستعار main لجميع الأدوات بحيث لا يرى المتصلون global أبدًا.

sessions_list

سرد الجلسات كمصفوفة من الصفوف. المعلمات:

  • kinds?: string[] عامل تصفية: أي من "main" | "group" | "cron" | "hook" | "node" | "other"
  • limit?: number الحد الأقصى للصفوف (الافتراضي: الافتراضي للخادم، مع تحديد حد أعلى، على سبيل المثال 200)
  • activeMinutes?: number فقط الجلسات التي تم تحديثها خلال N دقيقة
  • messageLimit?: number 0 = لا توجد رسائل (الافتراضي 0)؛ >0 = تضمين آخر N رسائل

السلوك:

  • messageLimit > 0 يجلب chat.history لكل جلسة ويتضمن آخر N رسائل.
  • يتم تصفية نتائج الأداة في مخرجات القائمة؛ استخدم sessions_history لرسائل الأداة.
  • عند التشغيل في جلسة وكيل معزولة (sandboxed)، فإن أدوات الجلسات تظهر بشكل افتراضي رؤية الجلسات المنشأة فقط (انظر أدناه).

شكل الصف (JSON):

  • key: مفتاح الجلسة (سلسلة نصية)
  • kind: main | group | cron | hook | node | other
  • channel: whatsapp | telegram | discord | signal | imessage | webchat | internal | unknown
  • displayName (تسمية عرض المجموعة إذا كانت متاحة)
  • updatedAt (مللي ثانية)
  • sessionId
  • model, contextTokens, totalTokens
  • thinkingLevel, verboseLevel, systemSent, abortedLastRun
  • sendPolicy (تجاوز الجلسة إذا تم تعيينه)
  • lastChannel, lastTo
  • deliveryContext (مُطَّبَق { channel, to, accountId } عند التوفر)
  • transcriptPath (مسار مستمد بأفضل جهد من دليل التخزين + sessionId)
  • messages? (فقط عندما يكون messageLimit > 0)

sessions_history

جلب النص المسجل لجلسة واحدة. المعلمات:

  • sessionKey (مطلوب؛ يقبل مفتاح الجلسة أو sessionId من sessions_list)
  • limit?: number الحد الأقصى للرسائل (الخادم يحدد حدًا أعلى)
  • includeTools?: boolean (الافتراضي false)

السلوك:

  • includeTools=false يرشح رسائل role: "toolResult".
  • يُرجع مصفوفة رسائل بتنسيق النص المسجل الخام.
  • عند إعطاء sessionId، يحل OpenClaw ذلك إلى مفتاح الجلسة المقابل (الأرقام المعرفية المفقودة تسبب خطأ).

sessions_send

إرسال رسالة إلى جلسة أخرى. المعلمات:

  • sessionKey (مطلوب؛ يقبل مفتاح الجلسة أو sessionId من sessions_list)
  • message (مطلوب)
  • timeoutSeconds?: number (الافتراضي >0؛ 0 = إرسال ونسيان)

السلوك:

  • timeoutSeconds = 0: يضيف إلى قائمة الانتظار ويعيد { runId, status: "accepted" }.
  • timeoutSeconds > 0: ينتظر حتى N ثانية للإكمال، ثم يعيد { runId, status: "ok", reply }.
  • إذا انتهت مهلة الانتظار: { runId, status: "timeout", error }. يستمر التشغيل؛ استدعِ sessions_history لاحقًا.
  • إذا فشل التشغيل: { runId, status: "error", error }.
  • تشغيل إعلان التسليم يتم بعد اكتمال التشغيل الأساسي وهو بأفضل جهد؛ status: "ok" لا يضمن تسليم الإعلان.
  • الانتظار يتم عبر بوابة agent.wait (على جانب الخادم) حتى لا يؤدي إعادة الاتصال إلى إسقاط الانتظار.
  • سياق الرسالة من وكيل إلى وكيل يتم حقنه للتشغيل الأساسي.
  • يتم حفظ الرسائل بين الجلسات مع message.provenance.kind = "inter_session" حتى يتمكن قراء النص المسجل من التمييز بين تعليمات الوكيل الموجهة والإدخال الخارجي من المستخدم.
  • بعد اكتمال التشغيل الأساسي، يقوم OpenClaw بتشغيل حلقة الرد:
    • الجولة 2+ تتبادل بين وكيل الطالب والوكيل الهدف.
    • الرد بـ REPLY_SKIP بالضبط لإيقاف التبادل.
    • الحد الأقصى للدورات هو session.agentToAgent.maxPingPongTurns (0–5، الافتراضي 5).
  • بمجرد انتهاء الحلقة، يقوم OpenClaw بتشغيل خطوة الإعلان من وكيل إلى وكيل (الوكيل الهدف فقط):
    • الرد بـ ANNOUNCE_SKIP بالضبط للبقاء صامتًا.
    • أي رد آخر يتم إرساله إلى قناة الهدف.
    • خطوة الإعلان تتضمن الطلب الأصلي + رد الجولة الأولى + أحدث رد تبادلي.

حقل القناة

  • للمجموعات، channel هو القناة المسجلة في إدخال الجلسة.
  • للدردشات المباشرة، channel يتم تعيينه من lastChannel.
  • للوظائف المجدولة/الخطافات/العقد، channel هو internal.
  • إذا كان مفقودًا، channel هو unknown.

الأمان / سياسة الإرسال

المنع القائم على السياسات حسب نوع القناة/الدردشة (ليس حسب معرف الجلسة).

{
  "session": {
    "sendPolicy": {
      "rules": [
        {
          "match": { "channel": "discord", "chatType": "group" },
          "action": "deny"
        }
      ],
      "default": "allow"
    }
  }
}

تجاوز وقت التشغيل (لكل إدخال جلسة):

  • sendPolicy: "allow" | "deny" (غير معين = يرث التكوين)
  • قابل للتعيين عبر sessions.patch أو /send on|off|inherit للمالك فقط (رسالة مستقلة).

نقاط التنفيذ:

  • chat.send / agent (البوابة)
  • منطق تسليم الرد التلقائي

sessions_spawn

إنشاء تشغيل وكيل فرعي في جلسة معزولة والإعلان عن النتيجة مرة أخرى إلى قناة الدردشة للطالب. المعلمات:

  • task (مطلوب)
  • label? (اختياري؛ يُستخدم للسجلات/واجهة المستخدم)
  • agentId? (اختياري؛ الإنشاء تحت معرف وكيل آخر إذا كان مسموحًا)
  • model? (اختياري؛ يتجاوز نموذج الوكيل الفرعي؛ القيم غير الصالحة تسبب خطأ)
  • thinking? (اختياري؛ يتجاوى مستوى التفكير لتشغيل الوكيل الفرعي)
  • runTimeoutSeconds? (الافتراضي هو agents.defaults.subagents.runTimeoutSeconds عند التعيين، وإلا 0؛ عند التعيين، يلغي تشغيل الوكيل الفرعي بعد N ثانية)
  • thread? (الافتراضي false؛ طلب التوجيه المرتبط بسلسلة المحادثة لهذا الإنشاء عند دعمه من قبل القناة/الملحق)
  • mode? (run|session؛ الافتراضي run، ولكن الافتراضي يصبح session عندما يكون thread=true؛ mode="session" يتطلب thread=true)
  • cleanup? (delete|keep، الافتراضي keep)
  • sandbox? (inherit|require، الافتراضي inherit؛ require يرفض الإنشاء ما لم يكن وقت تشغيل الهدف الفرعي معزولًا)
  • attachments? (مصفوفة اختيارية للملفات المضمنة؛ وقت تشغيل الوكيل الفرعي فقط، ACP يرفض). كل إدخال: { name, content, encoding?: "utf8" | "base64", mimeType? }. يتم تجسيد الملفات في مساحة العمل الفرعية في .openclaw/attachments/<uuid>/. يُرجع إيصالًا مع sha256 لكل ملف.
  • attachAs? (اختياري؛ { mountPath? } تلميح محجوز لتطبيقات التثبيت المستقبلية)

قائمة السماح:

  • agents.list[].subagents.allowAgents: قائمة معرفات الوكلاء المسموح بها عبر agentId (["*"] للسماح بأي). الافتراضي: فقط وكيل الطالب.
  • حارس توريث العزل: إذا كانت جلسة الطالب معزولة، فإن sessions_spawn يرفض الأهداف التي ستعمل بدون عزل.

الاكتشاف:

  • استخدم agents_list لاكتشاف معرفات الوكلاء المسموح بها لـ sessions_spawn.

السلوك:

  • يبدأ جلسة جديدة agent:<agentId>:subagent:<uuid> مع deliver: false.
  • الوكلاء الفرعيون لديهم بشكل افتراضي مجموعة الأدوات الكاملة مطروحًا منها أدوات الجلسات (قابل للتكوين عبر tools.subagents.tools).
  • لا يُسمح للوكلاء الفرعيين باستدعاء sessions_spawn (لا إنشاء وكيل فرعي → وكيل فرعي).
  • دائمًا غير محظور: يعيد { status: "accepted", runId, childSessionKey } فورًا.
  • مع thread=true، يمكن لوصلات القنوات ربط التسليم/التوجيه بهدف سلسلة المحادثة (دعم Discord يتم التحكم فيه بواسطة session.threadBindings.* و channels.discord.threadBindings.*).
  • بعد الاكتمال، يقوم OpenClaw بتشغيل خطوة إعلان الوكيل الفرعي وينشر النتيجة إلى قناة الدردشة للطالب.
    • إذا كان رد المساعد النهائي فارغًا، يتم تضمين أحدث toolResult من سجل الوكيل الفرعي كـ Result.
  • الرد بـ ANNOUNCE_SKIP بالضبط أثناء خطوة الإعلان للبقاء صامتًا.
  • يتم تطبيع ردود الإعلان إلى Status/Result/Notes؛ Status يأتي من نتيجة وقت التشغيل (وليس نص النموذج).
  • يتم أرشفة جلسات الوكيل الفرعي تلقائيًا بعد agents.defaults.subagents.archiveAfterMinutes (الافتراضي: 60).
  • تتضمن ردود الإعلان سطر إحصائيات (وقت التشغيل، الرموز، sessionKey/sessionId، مسار النص المسجل، والتكلفة الاختيارية).

رؤية الجلسة المعزولة

يمكن تحديد نطاق أدوات الجلسات لتقليل الوصول عبر الجلسات. السلوك الافتراضي:

  • tools.sessions.visibility الافتراضي هو tree (الجلسة الحالية + جلسات الوكيل الفرعي المنشأة).
  • للجلسات المعزولة، يمكن لـ agents.defaults.sandbox.sessionToolsVisibility تحديد الرؤية بقوة.

التكوين:

{
  tools: {
    sessions: {
      // "self" | "tree" | "agent" | "all"
      // default: "tree"
      visibility: "tree",
    },
  },
  agents: {
    defaults: {
      sandbox: {
        // default: "spawned"
        sessionToolsVisibility: "spawned", // or "all"
      },
    },
  },
}

ملاحظات:

  • self: فقط مفتاح الجلسة الحالي.
  • tree: الجلسة الحالية + الجلسات المنشأة بواسطة الجلسة الحالية.
  • agent: أي جلسة تنتمي إلى معرف الوكيل الحالي.
  • all: أي جلسة (الوصول عبر الوكلاء لا يزال يتطلب tools.agentToAgent).
  • عندما تكون الجلسة معزولة و sessionToolsVisibility="spawned"، يحدد OpenClaw الرؤية إلى tree حتى إذا قمت بتعيين tools.sessions.visibility="all".

تقليم الجلساتالذاكرة