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

جسر Cordis

يدمج جسر Cordis محرك DeepSeek Harness ‏(DSH) داخل الواجهة الخلفية لـ Libre WebUI. يعمل DSH كشجرة إضافات داخل بيئة تشغيل Cordis يستضيفها Libre WebUI، فتتاح إمكاناته كخدمات Cordis بدلًا من وحدات مستوردة.

الجسر معطّل افتراضيًا. لا يحدث شيء مما تصفه هذه الصفحة قبل أن يفعّله المشغّل (راجع تهيئة Cordis).

لماذا نستخدم جسرًا بدلًا من دمج مباشر

استيراد حزم DSH من خدمات Libre WebUI أقصر، لكنه أسوأ من ناحية التصميم. فالاستيراد المباشر يجعل المحرك اعتمادًا وقت الترجمة؛ وبالتالي يتطلب تغيير محوّل النموذج أو استبدال حلقة الوكيل أو إزالة المحرك تعديل Libre WebUI وإعادة نشره.

يعكس الجسر هذه العلاقة. يعتمد Libre WebUI على عقد مجرّد واحد، وتحدد وثيقة تركيب Cordis ما يحقق هذا العقد:

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

الطبقات

تبقى اعتمادات DSH الفعلية داخل backend/src/cordis/dsh/. وتستخدم المسارات وخدمات التطبيق عقود الجسر. أما برنامج تشغيل Work فله تركيب مستقل في الذاكرة، ولا يحمّل إضافات نظام ملفات المضيف مطلقًا.

العقود

يوجد العقد في backend/src/cordis/contracts.ts. وهو محدود عمدًا بالبنى التي تحتاجها واجهة API في Libre WebUI، دون استخدام مصطلحات المحرك الداخلية.

العقدالغرض
DshEngine.status()حالة دورة حياة كل خدمة في المحرك (pending / ready / failed)
DshEngine.modelConfiguration()النموذج والمزوّد الافتراضيان للتركيب الجاري
DshEngine.listSessions()ملخصات الجلسات، بدءًا بالأحدث
DshEngine.getSession(id)جلسة واحدة مع رسائلها المسقطة
DshEngine.createSession(opts)حجز معرّف جلسة ودليل عمل
DshEngine.updateSessionSettings(id, settings)حفظ الاختيار الفعلي للنموذج ووضع صلاحيات نظام الملفات الأصلي عندما تكون الجلسة خاملة
DshEngine.decideApproval(id, approvalId, decision)حسم طلب موافقة أصلي معلّق على أداة للجلسة المالكة له
DshEngine.deleteSession(id)إنهاء جلسة والتخلص من وكيلها
DshEngine.listAgents()الوكلاء الجاريون، مع تمييز الوكيل الجذري والفرعي
DshEngine.listTools()الأدوات المتاحة للنموذج التي سجّلها المحرك
DshEngine.sendMessage(id, txt)بدء دورة وإرجاع مقبض تدفق
DshEngine.cancel(id)إلغاء الدورة الجارية لجلسة

يُنشر العقد بوصفه خدمة Cordis باسم libreDshEngine، فيقرأه المستهلك عبر ctx.get('libreDshEngine') دون استيراد وحدة الجسر.

يحمل EngineStreamChunk الأنواع text وreasoning وtool-call وtool-result وapproval-request وapproval-decision وerror وdone. تُوجّه الإطارات الحية بحسب الوكيل والجلسة المالكين لها؛ ولا تُرسل رسالة المساعد الدائمة المقابلة مرة ثانية. يعيد sendMessage مقبضًا تعيد دالته subscribe تشغيل كل ما سبق إرساله، فلا يمكن فقدان أول رمز سريع بين بدء المحرك للدورة وإرفاق معالج HTTP لمستمعه.

تسلسل دورة محادثة واحدة

يُستخدم NDJSON بدلًا من WebSocket لأن الدورة تمثل تسلسلًا واحدًا من الخادم إلى العميل بعد الطلب. إبقاؤها ضمن POST يجنب مصافحة ثانية وتذكرة وبروتوكول إعادة اتصال، ويُبقي الدورة بأكملها داخل طلب واحد موثّق.

DONE وPENDING

يفعّل Cordis الإضافة عندما تتوفر الخدمات التي تعلنها، ولذلك يقضي الصف وقتًا في حالات لم يبدأ فيها التشغيل بعد. هناك مفهومان منفصلان مهمان؛ والخلط بينهما أكثر أسباب المحرك الصامت شيوعًا.

حالة إدخال المحمّل. يتتبع المحمّل كل صف عبر PENDING → LOADING → ACTIVE أو FAILED. ويظل الصف الذي تنقصه خدمات معلنة معلّقًا إلى أجل غير محدد بدلًا من الفشل، ولذلك قد يبدأ محرك ذو تركيب غير مكتمل لكنه لا يقدم أي شيء.

توفر الخدمة. يبلّغ المضيف عن كل خدمة متوقعة كما يلي:

الحالةالمعنىالسبب
pendingغير مسجلة في السياقالصف الموفّر لم يتفعّل أو أنه معطّل
readyمسجلة وقابلة للاستخدامالصف الموفّر تفعّل
failedمعلنة لكن غير قابلة للاستخدامتُبلّغ مع سلسلة detail

يسرد host.status() جميع الخدمات المتوقعة مع توفرها، ويسمّي الخدمات المطلوبة المفقودة؛ وتعرض GET /api/cordis/health المعلومات نفسها. إذا أغفل التركيب خدمة مطلوبة، يصدر خطأ عند البدء بدلًا من نشر محرك يجيب بقوائم فارغة.

من السهل الخطأ في سلسلتي الاعتماد التاليتين:

  • لا يمكن لـ dsh-tools البدء دون systemPrompt.
  • لا يمكن لـ dsh-agent-loop البدء حتى تتوفر agents وsessions وllm وtools وsystemPrompt وsessionProjections جميعًا.

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

تهيئة المزوّدين

يخدم الصف المرفق libre-webui-llm-adapter مزوّدي النماذج المهيّأين في Libre WebUI. ويختار منتقي النماذج في صفحة المحرك نموذج مزوّد لجلسة دون استبدال هذا الصف.

تُطبّق تعديلات صفوف الإضافات في التركيب عند بدء المضيف التالي. أعد تشغيل الواجهة الخلفية، أو عطّل Cordis وأعد تفعيله عندما يكون مفتاح المسؤول غير مقفل. تبقى الجلسات المحفوظة في المخزن المحدد وتستأنف عبر التركيب الحالي.

يمكن لكود التكامل الموثوق استخدام واجهات دورة الحياة في محمّل Cordis مباشرة. لا يوفّر الجسر نقطة نهاية لتبديل المحوّل، ولا يستعيد المحوّل السابق تلقائيًا إذا فشل البديل.

التراجع

إنهاء ليفة الجذر للمضيف يزيل كل ما ثبّته المحرك. علاقة الملكية هذه هي الضمان بأكمله، وهي تتحقق للأسباب التالية:

  • تسجّل الإضافات الخدمات، فتُسحب الخدمات مع الليفة التابعة لها.
  • تُسجّل اشتراكات session/event داخل منشئ الجسر نفسه، وتملكها ليفة صف الجسر.
  • يتتبع الجسر مقابض الوكلاء ويتخلص منها في أثر التنظيف الخاص به.
  • ينهي المضيف سياق الجذر الذي يملك كل الصفوف.

تكرار stopCordisHost() لا يغير النتيجة، وهو موصول بتسلسل إيقاف الواجهة الخلفية، فتُحرر مؤقتات المحرك ومقابض الملفات بدلًا من تركها حتى خروج العملية.

هوية الجلسة واستدامتها

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

يلغي حذف الجلسة وكيلها وينهيه قبل إزالة أثرها المحفوظ. يتحقق محوّل حذف JSONL المحلي من مسارات المخزن والجلسة ويرفض الروابط الرمزية. تعيد أنظمة الاستدامة الخلفية المخصصة التي لا تدعم الحذف خطأ بدلًا من الادعاء بإزالة البيانات.

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

محرك المضيف ميزة للنمط الفردي ذي النسخة الواحدة. لا تستطيع عمليات نشر الفرق تحميل بيئة JSONL المحلية الخاصة به. يستخدم Work المعزول بدلًا منها مستودعات SQL الموجودة للمهام والتشغيل والرسائل والموافقات والأحداث.

واجهة HTTP

الطريقةالمسارالغرض
GET/api/cordis/healthحالة الجسر؛ دون مصادقة
GET/api/cordis/sessionsسرد الجلسات
POST/api/cordis/sessionsإنشاء جلسة
GET/api/cordis/sessions/:idقراءة جلسة ورسائلها
DELETE/api/cordis/sessions/:idإنهاء جلسة
POST/api/cordis/sessions/:id/messagesإرسال رسالة وتدفق NDJSON
POST/api/cordis/sessions/:id/cancelإلغاء الدورة الجارية
GET/api/cordis/agentsسرد الوكلاء الجاريين
GET/api/cordis/toolsسرد الأدوات المسجلة

تتطلب كل المسارات عدا /health جلسة مسؤول موثّقة، وتعيد 503 مع code بقيمة CORDIS_DISABLED أو CORDIS_STARTING أو CORDIS_UNAVAILABLE ما دام الجسر عاجزًا عن خدمة الطلبات.

صفحة محرك Cordis في Libre WebUI تعرض قائمة الجلسات وأدوات المحرك المسجلة ونص محادثة متدفقًا.

الصفحة هي frontend/src/pages/CordisPage.tsx، ويمكن الوصول إليها عبر /cordis من الشريط الجانبي. تسرد الجلسات والأدوات المسجلة، وتنشئ الجلسات، وتبث الدورة في نص المحادثة. عندما يكون الجسر معطّلًا أو يتعذر بدءه، تعرض السبب بدلًا من قائمة فارغة، لأن «لا توجد جلسات» و«لا يوجد محرك» سيبدوان متطابقين خلاف ذلك.

عميل المتصفح هو frontend/src/utils/api/cordisApi.ts. يتعامل مع هذه الواجهة فقط، ولا يستورد أي نوع من الواجهة الخلفية أو حزمة @deepseek-ai/*، لذلك يظل المحرك قابلًا للاستبدال دون تغيير الواجهة الأمامية. تُستهلك الدورة عبر sendMessage(sessionId, text, { onChunk })؛ ويحلل العميل JSON المفصول بأسطر بنفسه ويتحمل تجزئة المقاطع بين قراءات الشبكة.

عناصر التحكم في محادثة المحرك

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

اختر نموذج مزوّد فعليًا في محرر الرسائل. يستخدم المنتقي النماذج المحلية ونماذج الإضافات المتاحة للمسؤول المسجّل دخوله، مع هوية المزوّد. اختيارات الشخصيات والوكلاء في Chat ليست معرّفات نماذج، ولا تحقن تعليماتها في محادثة المحرك. تُتجاهل ترويسات نماذج الشخصيات القديمة التي فشلت عند استنتاج النموذج الافتراضي، دون تغيير السجل المحفوظ.

لكل جلسة إعداد للقراءة فقط أو الكتابة في مساحة العمل الخاص بها، وتفرضه سياسة نظام الملفات في DSH وحدود مساحة العمل التي يعتمدها الجسر بعد تسوية المسارات. يعرض المحرر نطاق مساحة العمل. تُحفظ الإعدادات كأحداث جلسة أصلية وتنجو من إعادة التشغيل؛ وتُرفض التغييرات أثناء نشاط الدورة.

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

نقاط نهاية المسؤول الإضافية هي:

الطريقةالمسارالغرض
GET/api/cordis/modelsنماذج المزوّدين المتاحة والنموذج الفعلي الافتراضي الحالي
PATCH/api/cordis/sessions/:id/settingsتعيين نموذج هذه الجلسة و/أو وضع صلاحياتها
POST/api/cordis/sessions/:id/approvals/:approvalIdحسم طلب معلّق بواسطة allowed-once أو rejected

استخدام المحرك في Chat

فعّل الوصول والسياسات → نماذج وكلاء CLI ومحرك Cordis معًا. يمكن للمسؤولين بعدها اختيار DeepSeek Harness في Chat. يتلقى كل طلب جلسة محرك عابرة جديدة تتضمن نص المحادثة المرفق بطلب Chat هذا. تبقى قاعدة بيانات Chat المعتادة مصدر الحقيقة؛ ولا تستطيع المحادثات غير المرتبطة أو التفرعات أو محاولات الإعادة مشاركة سجل محرك غير مرئي. يُزال سجل المحرك العابر بعد الاكتمال أو الإلغاء، ولا يظهر في صفحة المحرك.

يسرد تركيب المزوّدين القياسي أيضًا خيارات DeepSeek Harness · النموذج (المزوّد) في مجموعة الوكلاء. تغلف معرّفاتها المحفوظة مسار المزوّد المؤهل نفسه الذي تستخدمه صفحة المحرك: dsh:lwui:ollama:<model> أو dsh:lwui:plugin:<plugin>:<model>، مع ترميز كل مكوّن مزوّد بالنسبة المئوية. تضيف وصلة DSH أصلية محلية اختيارية خيارات dsh:native:<provider>:<model> من كتالوج النماذج الحي لتلك النسخة. تعيد هذه الخيارات استخدام تهيئة المزوّد الأصلي وبيانات اعتماده. ثبّت الحزمة المستقلة المرخّصة Apache-2.0 من libre-webui/dsh-native-provider، أو جهّز حزمة من توزيعة Libre WebUI. يستخدم كلاهما اسم الحزمة @libre-webui/dsh-native-provider ويحتفظ بمفاتيح المزوّد داخل DSH الأصلي. تتطلب الوصلة مضيف Unix وحساب نظام تشغيل مشتركين ومقبس Unix خاصًا؛ ولا تستطيع عزل التطبيقات التي تشارك ذلك الحساب. لا تعرض إلا استدلال النماذج، دون جلسات وكلاء أصلية أو تنفيذ أدوات أصلية. راجع دليل التهيئة للتثبيت وإعادة تشغيل الملفات التعريفية والترقية والإزالة. يؤدي غياب الوصلة أو النموذج المحدد إلى فشل دون تغيير المزوّد. تظهر الاستدعاءات الأصلية أيضًا في استخدام المزود مع النموذج المختار والرموز المبلّغ عنها وزمن الاستجابة وحالة النتيجة. يحتفظ الملف التعريفي الأساسي dsh بالنموذج الافتراضي للتركيب الجاري. تعرض تراكيب المحوّلات المخصصة هذا الملف الأساسي دون الإعلان عن تجاوزات لمزوّدي Libre WebUI غير مدعومة.

تحوّل العناوين وملخصات التفكير اختيار DSH إلى مزوّده الأساسي، وتُرسل طلبًا نصيًا مباشرًا دون أدوات أو جلسة وكيل. يقرأ طلب الملف الأساسي القيم الافتراضية للمحرك الجاري، بما في ذلك تجاوزات صف الجسر، بدلًا من تخمينها من كتالوج المزوّدين الحالي. تحتاج المحوّلات المخصصة إلى نموذج مهمة Ollama أو إضافة مهيّأ صراحة لهذه الميزات. يؤدي عدم توفر المزوّد المختار إلى الفشل المعتاد أو معاينة عنوان محلية، لا إلى طلب لمزوّد آخر.

تخدم الطلب إعدادات المزوّد وبيانات الاعتماد الخاصة بالمسؤول الموثّق. لا تُختار بيانات اعتماد مسؤول آخر ضمنيًا. تبقى مساحة عمل Cordis المهيّأة هي الافتراضية؛ ولا يستبدلها Chat بالدليل المنزلي لمستخدم الخادم.

Work المعزول

عندما يكون Cordis مفعّلًا، يوفّر Work عنصر المحرك المنفصل بخياري Libre WebUI وDeepSeek Harness. يحتفظ منتقي النماذج بأسماء النماذج وهويات المزوّدين المعتادة. داخليًا، يُخزّن اختيار DSH بالشكل dsh:<model> لمزوّدي LWUI. أما الاختيارات الأصلية لـ DSH فتخزّن providerType: dsh ومعرّف المزوّد الأصلي الدقيق ومعرّف النموذج الخام. تظل فحوص دعم الأدوات والوصول المعتادة سارية؛ وتضيف بيانات الاعتماد الأصلية شرط المسؤول النشط.

تنشئ كل عملية تشغيل حلقة وكيل DSH معزولة في الذاكرة. يتلقى محوّل النموذج نص Work الحالي وبيانات المزوّد الوصفية والصور ومخططات الأدوات. تنتظر أجسام الأدوات فقط النتائج التي يعيدها Work؛ ولا تستطيع قراءة ملفات المضيف أو بدء عملياته.

يبقى Work مسؤولًا عن التحقق من الوسائط، وطلب الموافقات، وتنفيذ الأدوات في بيئة مساحة العمل، وتسجيل النتائج وحالة إعادة تشغيل المزوّد في SQL، وفرض الميزانيات، ونشر الأحداث. تنتج الأداة المرفوضة نتيجة الرفض المعتادة. ينهي الإلغاء DSH ويتبع مسار تنظيف حاوية Work الحالي. بعد استعادة العامل، يتلقى برنامج تشغيل DSH جديد سياق Work المستعاد ولا يعيد الآثار الجانبية للأدوات المكتملة.

لا يحتاج تكامل Work إلى تركيب محرك المضيف أو مخزن جلسات JSONL. وهو يتبع قواعد تشغيل ونشر Docker/Kubernetes الحالية في Work، بما فيها متطلبات الاستدامة المشتركة لوضع الفريق.

حدود الأمان

صفحة المحرك ووكيل Chat على المضيف مخصصان للمسؤولين فقط. جلسات المحرك وحدة تحكم مشتركة للمسؤولين، بما في ذلك مطالبات النظام، وليست مساحة عمل لكل مستخدم. لا تستطيع الحسابات العادية قراءتها أو إنشاءها أو تعديلها أو إلغاءها عبر API.

تحصر أدوات نظام ملفات المضيف المرفقة القراءة والكتابة في مساحة العمل المهيّأة عبر الأهداف الفعلية لنظام الملفات بعد تسوية المسارات، بما فيها حل الروابط الرمزية. يجب أن تبقى تجاوزات دليل العمل للجلسة ضمن تلك المساحة. وتظل سياسة التعديل الأصلية في DSH وقرارات الموافقة لمرة واحدة في المحرك سارية. إضافات التركيب التي يثبتها المشغّل كود خادم موثوق، وقد تمنح إمكانات إضافية. موافقات المحرك منفصلة عن مسار الموافقة والتنفيذ داخل الحاويات في Work.

برنامج تشغيل DSH الخاص بـ Work مستقل: لا يحمّل إضافات نظام ملفات المضيف أو الصدفة أو الاستدامة، ولا يمكنه التنفيذ إلا عبر صلاحيات Work وبيئته المعزولة الحالية. تبقى مزوّدات النماذج البعيدة اختيارية، وتستخدم مسار المزوّد المهيّأ للحساب المحدد.