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

Documentation Index

Fetch the complete documentation index at: https://docs.openclaw.ai/llms.txt

Use this file to discover all available pages before exploring further.

تُعد نواة دورة القناة آلة الحالة الواردة المشتركة التي تحوّل حدث منصة مُطبَّعًا إلى دورة وكيل. توفّر Plugins القنوات حقائق المنصة واستدعاء التسليم. تتولى النواة التنسيق: الاستقبال، والتصنيف، والفحص الأولي، والحل، والتفويض، والتجميع، والتسجيل، والإرسال، والإنهاء. استخدم هذا عندما يكون Plugin الخاص بك ضمن المسار الساخن للرسائل الواردة. بالنسبة للأحداث غير الرسائل (أوامر الشرطة المائلة، والنوافذ الشرطية، وتفاعلات الأزرار، وأحداث دورة الحياة، والتفاعلات، وحالة الصوت)، أبقها محلية داخل Plugin. لا تملك النواة إلا الأحداث التي قد تصبح دورة نصية للوكيل.
يتم الوصول إلى النواة عبر وقت تشغيل Plugin المحقون باسم runtime.channel.turn.*. يُصدَّر نوع وقت تشغيل Plugin من openclaw/plugin-sdk/core، لذا يمكن لـ Plugins الأصلية التابعة لأطراف ثالثة استخدام نقاط الدخول هذه بالطريقة نفسها التي تستخدمها Plugins القنوات المضمّنة.

لماذا توجد نواة مشتركة

تكرر Plugins القنوات تدفق الوارد نفسه: التطبيع، والتوجيه، والبوابات، وبناء سياق، وتسجيل بيانات تعريف الجلسة، وإرسال دورة الوكيل، وإنهاء حالة التسليم. من دون نواة مشتركة، يجب تطبيق أي تغيير على بوابة الإشارة، أو الردود المرئية المقتصرة على الأدوات، أو بيانات تعريف الجلسة، أو السجل المعلّق، أو إنهاء الإرسال لكل قناة على حدة. تحافظ النواة عمدًا على فصل أربعة مفاهيم:
  • ConversationFacts: من أين أتت الرسالة
  • RouteFacts: أي وكيل وجلسة يجب أن يعالجاها
  • ReplyPlanFacts: إلى أين يجب أن تذهب الردود المرئية
  • MessageFacts: ما المتن والسياق التكميلي اللذان يجب أن يراهما الوكيل
تميز رسائل Slack المباشرة، ومواضيع Telegram، وخيوط Matrix، وجلسات مواضيع Feishu بين هذه الأمور عمليًا. التعامل معها كمعرّف واحد يسبب انحرافًا بمرور الوقت.

دورة حياة المراحل

تشغّل النواة خط الأنابيب الثابت نفسه بغض النظر عن القناة:
  1. ingest — يحوّل المحوّل حدث منصة خامًا إلى NormalizedTurnInput
  2. classify — يصرّح المحوّل بما إذا كان هذا الحدث يمكنه بدء دورة وكيل
  3. preflight — ينفّذ المحوّل إزالة التكرار، وصدى الذات، والإثراء، وتأجيل المعالجة، وفك التشفير، والملء المسبق الجزئي للحقائق
  4. resolve — يعيد المحوّل دورة مجمّعة بالكامل (المسار، وخطة الرد، والرسالة، والتسليم)
  5. authorize — تُطبَّق سياسة الرسائل المباشرة، والمجموعات، والإشارات، والأوامر على الحقائق المجمّعة
  6. assemble — يُبنى FinalizedMsgContext من الحقائق عبر buildContext
  7. record — تُحفظ بيانات تعريف الجلسة الواردة وآخر مسار
  8. dispatch — تُنفَّذ دورة الوكيل عبر مرسل الكتل المخزّن مؤقتًا
  9. finalize — يعمل onFinalize الخاص بالمحوّل حتى عند حدوث خطأ في الإرسال
تصدر كل مرحلة حدث سجل منظمًا عند توفير استدعاء log. راجع قابلية الملاحظة.

أنواع القبول

لا تطرح النواة خطأ عندما تكون الدورة محجوبة. بل تعيد ChannelTurnAdmission:
النوعمتى
dispatchتُقبل الدورة. تعمل دورة الوكيل ويُستخدم مسار الرد المرئي.
observeOnlyتعمل الدورة من البداية إلى النهاية لكن محوّل التسليم لا يرسل شيئًا مرئيًا. يُستخدم لوكلاء مراقبة البث وتدفقات الوكلاء المتعددين السلبية الأخرى.
handledتم استهلاك حدث منصة محليًا (دورة حياة، تفاعل، زر، نافذة شرطية). تتجاوز النواة الإرسال.
dropمسار تخطّي. اختياريًا، يحافظ recordHistory: true على الرسالة في سجل المجموعة المعلّق كي تتوفر للذكر المستقبلي سياقًا.
يمكن أن يأتي القبول من classify (صرّحت فئة الحدث بأنه لا يمكنه بدء دورة)، أو من preflight (إزالة التكرار، وصدى الذات، وذكر مفقود مع تسجيل السجل)، أو من resolveTurn نفسه.

نقاط الدخول

يعرض وقت التشغيل ثلاث نقاط دخول مفضلة كي تتمكن المحوّلات من الاشتراك بالمستوى الذي يطابق القناة.
runtime.channel.turn.run(...)             // adapter-driven full pipeline
runtime.channel.turn.runPrepared(...)     // channel owns dispatch; kernel runs record + finalize
runtime.channel.turn.buildContext(...)    // pure facts to FinalizedMsgContext mapping
يبقى مساعدان أقدم في وقت التشغيل متاحين لتوافق Plugin SDK:
runtime.channel.turn.runResolved(...)      // deprecated compatibility alias; prefer run
runtime.channel.turn.dispatchAssembled(...) // deprecated compatibility alias; prefer run or runPrepared

run

استخدمه عندما تستطيع قناتك التعبير عن تدفقها الوارد بوصفه ChannelTurnAdapter<TRaw>. يحتوي المحوّل على استدعاءات لـ ingest، وclassify اختياري، وpreflight اختياري، وresolveTurn إلزامي، وonFinalize اختياري.
await runtime.channel.turn.run({
  channel: "tlon",
  accountId,
  raw: platformEvent,
  adapter: {
    ingest(raw) {
      return {
        id: raw.messageId,
        timestamp: raw.timestamp,
        rawText: raw.body,
        textForAgent: raw.body,
      };
    },
    classify(input) {
      return { kind: "message", canStartAgentTurn: input.rawText.length > 0 };
    },
    async preflight(input, eventClass) {
      if (await isDuplicate(input.id)) {
        return { admission: { kind: "drop", reason: "dedupe" } };
      }
      return {};
    },
    resolveTurn(input) {
      return buildAssembledTurn(input);
    },
    onFinalize(result) {
      clearPendingGroupHistory(result);
    },
  },
});
run هو الشكل المناسب عندما تمتلك القناة منطق محوّل صغيرًا وتستفيد من امتلاك دورة الحياة عبر الخطافات.

runPrepared

استخدمه عندما تمتلك القناة مرسلًا محليًا معقدًا يتضمن معاينات، وإعادة محاولات، وتعديلات، أو تمهيد خيط يجب أن يبقى مملوكًا للقناة. لا تزال النواة تسجل الجلسة الواردة قبل الإرسال وتعرض DispatchedChannelTurnResult موحدًا.
const { dispatchResult } = await runtime.channel.turn.runPrepared({
  channel: "matrix",
  accountId,
  routeSessionKey,
  storePath,
  ctxPayload,
  recordInboundSession,
  record: {
    onRecordError,
    updateLastRoute,
  },
  onPreDispatchFailure: async (err) => {
    await stopStatusReactions();
  },
  runDispatch: async () => {
    return await runMatrixOwnedDispatcher();
  },
});
تستخدم القنوات الغنية (Matrix، وMattermost، وMicrosoft Teams، وFeishu، وQQ Bot) runPrepared لأن مرسلها ينسّق سلوكًا خاصًا بالمنصة يجب ألا تتعلمه النواة.

buildContext

دالة نقية تربط حزم الحقائق إلى FinalizedMsgContext. استخدمها عندما تبني قناتك جزءًا من خط الأنابيب يدويًا لكنها تريد شكل سياق متسقًا.
const ctxPayload = runtime.channel.turn.buildContext({
  channel: "googlechat",
  accountId,
  messageId,
  timestamp,
  from,
  sender,
  conversation,
  route,
  reply,
  message,
  access,
  media,
  supplemental,
});
يكون buildContext مفيدًا أيضًا داخل استدعاءات resolveTurn عند تجميع دورة لـ run.
لا تزال مساعدات SDK المتقادمة مثل dispatchInboundReplyWithBase تعبر عبر مساعد دورة مجمّعة. يجب أن تستخدم شيفرة Plugin الجديدة run أو runPrepared.

أنواع الحقائق

الحقائق التي تستهلكها النواة من محوّلك حيادية تجاه المنصة. ترجم كائنات المنصة إلى هذه الأشكال قبل تسليمها إلى النواة.

NormalizedTurnInput

الحقلالغرض
idمعرّف رسالة ثابت يُستخدم لإزالة التكرار والسجلات
timestampوقت اختياري بالمللي ثانية منذ الحقبة
rawTextالمتن كما استُقبل من المنصة
textForAgentمتن منظف اختياري للوكيل (إزالة الإشارة، تقليم الكتابة)
textForCommandsمتن اختياري يُستخدم لتحليل /command
rawمرجع تمرير اختياري لاستدعاءات المحوّل التي تحتاج إلى الأصل

ChannelEventClass

الحقلالغرض
kindmessage, command, interaction, reaction, lifecycle, unknown
canStartAgentTurnإذا كانت false فتعيد النواة { kind: "handled" }
requiresImmediateAckتلميح للمحوّلات التي تحتاج إلى ACK قبل الإرسال

SenderFacts

الحقلالغرض
idمعرّف مرسل ثابت على المنصة
nameاسم العرض
usernameالمعرّف إذا كان مختلفًا عن name
tagمميّز بنمط Discord أو وسم المنصة
rolesمعرّفات الأدوار، تُستخدم لمطابقة قائمة سماح أدوار الأعضاء
isBottrue عندما يكون المرسل روبوتًا معروفًا (تستخدمها النواة للإسقاط)
isSelftrue عندما يكون المرسل هو الوكيل المكوَّن نفسه
displayLabelتسمية معروضة مسبقًا لنص الغلاف

ConversationFacts

الحقلالغرض
kinddirect، أو group، أو channel
idمعرّف المحادثة المستخدم للتوجيه
labelتسمية بشرية للغلاف
spaceIdمعرّف مساحة خارجي اختياري (مساحة عمل Slack، أو خادم Matrix المنزلي)
parentIdمعرّف المحادثة الخارجي عندما يكون هذا خيطًا
threadIdمعرّف الخيط عندما تكون هذه الرسالة داخل خيط
nativeChannelIdمعرّف القناة الأصلي للمنصة عندما يختلف عن معرّف التوجيه
routePeerالند المستخدم لبحث resolveAgentRoute

RouteFacts

الحقلالغرض
agentIdالوكيل الذي يجب أن يتعامل مع هذه الدورة
accountIdتجاوز اختياري (القنوات متعددة الحسابات)
routeSessionKeyمفتاح الجلسة المستخدم للتوجيه
dispatchSessionKeyمفتاح الجلسة المستخدم عند الإرسال عندما يختلف عن مفتاح المسار
persistedSessionKeyمفتاح الجلسة المكتوب إلى بيانات تعريف الجلسة المحفوظة
parentSessionKeyالأصل للجلسات المتفرعة/المترابطة بخيوط
modelParentSessionKeyالأصل من جهة النموذج للجلسات المتفرعة
mainSessionKeyتثبيت مالك الرسالة المباشرة الرئيسي للمحادثات المباشرة
createIfMissingالسماح لخطوة التسجيل بإنشاء صف جلسة مفقود

ReplyPlanFacts

الحقلالغرض
toهدف الرد المنطقي المكتوب في السياق To
originatingToهدف السياق الأصلي (OriginatingTo)
nativeChannelIdمعرّف القناة الأصلي للمنصة المستخدم للتسليم
replyTargetوجهة الرد المرئية النهائية إذا كانت تختلف عن to
deliveryTargetتجاوز تسليم على مستوى أدنى
replyToIdمعرّف الرسالة المقتبسة/المثبتة
replyToIdFullمعرّف الاقتباس الكامل عندما تملك المنصة كليهما
messageThreadIdمعرّف سلسلة النقاش وقت التسليم
threadParentIdمعرّف الرسالة الأصلية لسلسلة النقاش
sourceReplyDeliveryModethread أو reply أو channel أو direct أو none

AccessFacts

يحمل AccessFacts القيم المنطقية التي تحتاجها مرحلة التفويض. يبقى تطابق الهوية داخل القناة: تستهلك النواة النتيجة فقط.
الحقلالغرض
dmقرار السماح/الإقران/الرفض للرسائل المباشرة وقائمة allowFrom
groupسياسة المجموعة، والسماح بالمسار، والسماح للمرسل، وقائمة السماح، ومتطلب الذكر
commandsتفويض الأوامر عبر المفوّضين المكوّنين
mentionsما إذا كان اكتشاف الذكر ممكنا وما إذا كان قد تم ذكر الوكيل

MessageFacts

الحقلالغرض
bodyنص المغلف النهائي (منسق)
rawBodyالنص الوارد الخام
bodyForAgentالنص الذي يراه الوكيل
commandBodyالنص المستخدم لتحليل الأوامر
envelopeFromتسمية المرسل المعروضة مسبقا للمغلف
senderLabelتجاوز اختياري للمرسل المعروض
previewمعاينة قصيرة منقحة للسجلات
inboundHistoryإدخالات السجل الوارد الحديثة عندما تحتفظ القناة بمخزن مؤقت

SupplementalContextFacts

يغطي السياق التكميلي سياق الاقتباس وإعادة التوجيه وتمهيد سلسلة النقاش. تطبق النواة سياسة contextVisibility المكوّنة. لا يوفر مهايئ القناة إلا الحقائق وأعلام senderAllowed حتى تبقى السياسة متسقة عبر القنوات.

InboundMediaFacts

تكون الوسائط مصاغة كحقائق. يبقى تنزيل المنصة، والمصادقة، وسياسة SSRF، وقواعد CDN، وفك التشفير محلية للقناة. تربط النواة الحقائق إلى MediaPath وMediaUrl وMediaType وMediaPaths وMediaUrls وMediaTypes وMediaTranscribedIndexes.

عقد المهايئ

للتشغيل الكامل run، يكون شكل المهايئ:
type ChannelTurnAdapter<TRaw> = {
  ingest(raw: TRaw): Promise<NormalizedTurnInput | null> | NormalizedTurnInput | null;
  classify?(input: NormalizedTurnInput): Promise<ChannelEventClass> | ChannelEventClass;
  preflight?(
    input: NormalizedTurnInput,
    eventClass: ChannelEventClass,
  ): Promise<PreflightFacts | ChannelTurnAdmission | null | undefined>;
  resolveTurn(
    input: NormalizedTurnInput,
    eventClass: ChannelEventClass,
    preflight: PreflightFacts,
  ): Promise<ChannelTurnResolved> | ChannelTurnResolved;
  onFinalize?(result: ChannelTurnResult): Promise<void> | void;
};
يعيد resolveTurn قيمة ChannelTurnResolved، وهي AssembledChannelTurn مع نوع قبول اختياري. يؤدي إرجاع { admission: { kind: "observeOnly" } } إلى تشغيل الدور من دون إنتاج مخرج مرئي. يظل المهايئ مالكا لاستدعاء التسليم؛ لكنه يصبح مجرد عملية بلا أثر لذلك الدور. يعمل onFinalize على كل نتيجة، بما في ذلك أخطاء الإرسال. استخدمه لمسح سجل المجموعة المعلق، وإزالة تفاعلات الإقرار، وإيقاف مؤشرات الحالة، وتفريغ الحالة المحلية.

مهايئ التسليم

لا تستدعي النواة المنصة مباشرة. تمرر القناة إلى النواة ChannelTurnDeliveryAdapter:
type ChannelTurnDeliveryAdapter = {
  deliver(payload: ReplyPayload, info: ChannelDeliveryInfo): Promise<ChannelDeliveryResult | void>;
  onError?(err: unknown, info: { kind: string }): void;
};

type ChannelDeliveryResult = {
  messageIds?: string[];
  threadId?: string;
  replyToId?: string;
  visibleReplySent?: boolean;
};
يستدعى deliver مرة واحدة لكل جزء رد مخزن مؤقتا. أعد معرّفات رسائل المنصة عندما تكون متاحة لدى القناة حتى يستطيع المرسل الحفاظ على مثبتات سلسلة النقاش وتحرير الأجزاء اللاحقة. للأدوار الخاصة بالمراقبة فقط، أعد { visibleReplySent: false } أو استخدم createNoopChannelTurnDeliveryAdapter().

خيارات التسجيل

تغلف مرحلة التسجيل recordInboundSession. يمكن لمعظم القنوات استخدام القيم الافتراضية. تجاوز عبر record:
record: {
  groupResolution,
  createIfMissing: true,
  updateLastRoute,
  onRecordError: (err) => log.warn("record failed", err),
  trackSessionMetaTask: (task) => pendingTasks.push(task),
}
ينتظر المرسل مرحلة التسجيل. إذا ألقى التسجيل خطأ، تشغل النواة onPreDispatchFailure (عند توفيره إلى runPrepared) ثم تعيد رمي الخطأ.

قابلية الملاحظة

تصدر كل مرحلة حدثا منظما عند توفير استدعاء log:
await runtime.channel.turn.run({
  channel: "twitch",
  accountId,
  raw,
  adapter,
  log: (event) => {
    runtime.log?.debug?.(`turn.${event.stage}:${event.event}`, {
      channel: event.channel,
      accountId: event.accountId,
      messageId: event.messageId,
      sessionKey: event.sessionKey,
      admission: event.admission,
      reason: event.reason,
    });
  },
});
المراحل المسجلة: ingest وclassify وpreflight وresolve وauthorize وassemble وrecord وdispatch وfinalize. تجنب تسجيل النصوص الخام؛ استخدم MessageFacts.preview للمعاينات القصيرة المنقحة.

ما يبقى محليا للقناة

تملك النواة التنسيق. وتظل القناة تملك:
  • وسائل نقل المنصة (Gateway وREST وwebsocket والاستقصاء وwebhooks)
  • حل الهوية ومطابقة اسم العرض
  • الأوامر الأصلية، وأوامر الشرطة المائلة، والإكمال التلقائي، والنوافذ، والأزرار، وحالة الصوت
  • عرض البطاقات والنوافذ والبطاقات التكيفية
  • مصادقة الوسائط، وقواعد CDN، والوسائط المشفرة، والتفريغ النصي
  • واجهات API للتحرير والتفاعل والتنقيح والحضور
  • الملء اللاحق وجلب السجل من جهة المنصة
  • تدفقات الإقران التي تتطلب تحققا خاصا بالمنصة
إذا بدأت قناتان تحتاجان إلى المساعد نفسه لأحد هذه الأمور، فاستخرج مساعد SDK مشتركا بدلا من دفعه إلى النواة.

الاستقرار

يعد runtime.channel.turn.* جزءا من سطح وقت تشغيل Plugin العام. يمكن الوصول إلى أنواع الحقائق (SenderFacts وConversationFacts وRouteFacts وReplyPlanFacts وAccessFacts وMessageFacts وSupplementalContextFacts وInboundMediaFacts) وأشكال القبول (ChannelTurnAdmission وChannelEventClass) عبر PluginRuntime من openclaw/plugin-sdk/core. تنطبق قواعد التوافق مع الإصدارات السابقة: حقول الحقائق الجديدة إضافية، ولا يعاد تسمية أنواع القبول، وتبقى أسماء نقطة الدخول مستقرة. يجب أن تمر احتياجات القنوات الجديدة التي تتطلب تغييرا غير إضافي عبر عملية ترحيل SDK الخاصة بالـ Plugin.

ذات صلة