الفروق
diffs هي أداة plugin اختيارية تحتوي على إرشادات نظام مضمّنة قصيرة ومهارة مصاحبة تحوّل محتوى التغييرات إلى عنصر فروق للقراءة فقط للوكلاء.
تقبل أحد الخيارين التاليين:
- النص
beforeوafter patchموحّد
- عنوان URL لعارض البوابة لعرضه في canvas
- مسار ملف مُصيَّر (PNG أو PDF) لتسليم الرسائل
- كلا المخرجين في استدعاء واحد
بداية سريعة
- فعّل plugin.
- استدعِ
diffsباستخدامmode: "view"للتدفقات التي يكون فيها canvas أولًا. - استدعِ
diffsباستخدامmode: "file"لتدفقات تسليم الملفات في الدردشة. - استدعِ
diffsباستخدامmode: "both"عندما تحتاج إلى كلا العنصرين.
تفعيل plugin
تعطيل إرشادات النظام المضمّنة
إذا كنت تريد إبقاء أداةdiffs مفعلة مع تعطيل إرشاداتها المضمّنة في system-prompt، فاضبط plugins.entries.diffs.hooks.allowPromptInjection على false:
before_prompt_build في plugin الفروق مع الإبقاء على plugin والأداة والمهارة المصاحبة متاحة.
إذا كنت تريد تعطيل كل من الإرشادات والأداة، فعطّل plugin بدلًا من ذلك.
سير عمل الوكيل المعتاد
- يستدعي الوكيل
diffs. - يقرأ الوكيل حقول
details. - ثم يقوم الوكيل بأحد ما يلي:
- يفتح
details.viewerUrlباستخدامcanvas present - يرسل
details.filePathباستخدامmessageمعpathأوfilePath - أو يفعل الأمرين معًا
- يفتح
أمثلة الإدخال
قبل وبعد:مرجع مُدخلات الأداة
كل الحقول اختيارية ما لم يُذكر خلاف ذلك:before(string): النص الأصلي. مطلوب معafterعند حذفpatch.after(string): النص المُحدَّث. مطلوب معbeforeعند حذفpatch.patch(string): نص diff موحّد. وهو متنافر معbeforeوafter.path(string): اسم ملف العرض لوضع before/after.lang(string): تلميح تجاوز اللغة لوضع before/after. القيم غير المعروفة تعود إلى نص عادي.title(string): تجاوز عنوان العارض.mode("view" | "file" | "both"): وضع الإخراج. القيمة الافتراضية هي الافتراضي الخاص بـ plugin عندdefaults.mode. الاسم المستعار المهجور:"image"يتصرف مثل"file"وما زال مقبولًا للتوافق مع الإصدارات السابقة.theme("light" | "dark"): سمة العارض. القيمة الافتراضية هي الافتراضي الخاص بـ plugin عندdefaults.theme.layout("unified" | "split"): تخطيط diff. القيمة الافتراضية هي الافتراضي الخاص بـ plugin عندdefaults.layout.expandUnchanged(boolean): يوسّع الأقسام غير المتغيرة عندما يكون السياق الكامل متاحًا. خيار لكل استدعاء فقط (وليس مفتاحًا افتراضيًا للـ plugin).fileFormat("png" | "pdf"): تنسيق الملف المُصيَّر. القيمة الافتراضية هي الافتراضي الخاص بـ plugin عندdefaults.fileFormat.fileQuality("standard" | "hq" | "print"): إعداد جودة مسبق لعرض PNG أو PDF.fileScale(number): تجاوز مقياس الجهاز (1-4).fileMaxWidth(number): أقصى عرض للتصيير بوحدات CSS pixel (640-2400).ttlSeconds(number): مدة صلاحية العنصر بالثواني لمخرجات العارض والملف المستقل. الافتراضي 1800، والحد الأقصى 21600.baseUrl(string): تجاوز أصل عنوان URL للعارض. يتجاوزviewerBaseUrlالخاص بـ plugin. يجب أن يكونhttpأوhttps، ومن دون query/hash.
format->fileFormatimageFormat->fileFormatimageQuality->fileQualityimageScale->fileScaleimageMaxWidth->fileMaxWidth
- الحد الأقصى لكل من
beforeوafterهو 512 KiB. - الحد الأقصى لـ
patchهو 2 MiB. - الحد الأقصى لـ
pathهو 2048 بايت. - الحد الأقصى لـ
langهو 128 بايت. - الحد الأقصى لـ
titleهو 1024 بايت. - حد تعقيد patch: 128 ملفًا كحد أقصى و120000 سطر إجماليًا.
- يتم رفض استخدام
patchمعbeforeأوafterمعًا. - حدود أمان الملفات المُصيَّرة (تنطبق على PNG وPDF):
fileQuality: "standard": حد أقصى 8 MP (8,000,000 بكسل مُصيَّر).fileQuality: "hq": حد أقصى 14 MP (14,000,000 بكسل مُصيَّر).fileQuality: "print": حد أقصى 24 MP (24,000,000 بكسل مُصيَّر).- لدى PDF أيضًا حد أقصى يبلغ 50 صفحة.
عقد تفاصيل الإخراج
تعيد الأداة بيانات وصفية منظَّمة ضمنdetails.
الحقول المشتركة للأوضاع التي تُنشئ عارضًا:
artifactIdviewerUrlviewerPathtitleexpiresAtinputKindfileCountmodecontext(agentIdوsessionIdوmessageChannelوagentAccountIdعند التوفر)
artifactIdexpiresAtfilePathpath(القيمة نفسها لـfilePath، لتوافق أداة الرسائل)fileBytesfileFormatfileQualityfileScalefileMaxWidth
format(القيمة نفسها لـfileFormat)imagePath(القيمة نفسها لـfilePath)imageBytes(القيمة نفسها لـfileBytes)imageQuality(القيمة نفسها لـfileQuality)imageScale(القيمة نفسها لـfileScale)imageMaxWidth(القيمة نفسها لـfileMaxWidth)
mode: "view": حقول العارض فقط.mode: "file": حقول الملف فقط، من دون عنصر عارض.mode: "both": حقول العارض بالإضافة إلى حقول الملف. إذا فشل تصيير الملف، فسيُعاد العارض معfileErrorوالاسم المستعار التوافقيimageError.
الأقسام غير المتغيرة المطوية
- يمكن للعارض أن يعرض أسطرًا مثل
N unmodified lines. - عناصر التحكم في التوسيع على هذه الأسطر مشروطة وليست مضمونة لكل نوع إدخال.
- تظهر عناصر التحكم في التوسيع عندما يحتوي diff المُصيَّر على بيانات سياق قابلة للتوسيع، وهو أمر شائع في مدخلات before/after.
- بالنسبة إلى كثير من مدخلات patch الموحّدة، لا تكون أجسام السياق المحذوفة متاحة في أجزاء patch المحللة، لذلك قد يظهر السطر من دون عناصر تحكم للتوسيع. هذا سلوك متوقَّع.
- ينطبق
expandUnchangedفقط عندما يكون هناك سياق قابل للتوسيع.
القيم الافتراضية للـ plugin
اضبط القيم الافتراضية على مستوى plugin في~/.openclaw/openclaw.json:
fontFamilyfontSizelineSpacinglayoutshowLineNumbersdiffIndicatorswordWrapbackgroundthemefileFormatfileQualityfileScalefileMaxWidthmode
viewerBaseUrl(string، اختياري)- بديل مملوك للـ plugin للروابط المعادة الخاصة بالعارض عندما لا يمرر استدعاء الأداة
baseUrl. - يجب أن يكون
httpأوhttps، ومن دون query/hash.
- بديل مملوك للـ plugin للروابط المعادة الخاصة بالعارض عندما لا يمرر استدعاء الأداة
إعدادات الأمان
security.allowRemoteViewer(boolean، الافتراضيfalse)false: تُرفَض الطلبات غير القادمة من loopback إلى مسارات العارض.true: يُسمح بالعارضات البعيدة إذا كان المسار المرمّز صالحًا.
دورة حياة العناصر والتخزين
- تُخزَّن العناصر ضمن المجلد الفرعي المؤقت:
$TMPDIR/openclaw-diffs. - تحتوي البيانات الوصفية لعنصر العارض على:
- معرّف عنصر عشوائي (20 حرف hex)
- رمزًا مميزًا عشوائيًا (48 حرف hex)
createdAtوexpiresAt- مسار
viewer.htmlالمخزَّن
- مدة الصلاحية الافتراضية للعنصر هي 30 دقيقة عند عدم تحديدها.
- الحد الأقصى المقبول لمدة صلاحية العارض هو 6 ساعات.
- تعمل عملية التنظيف بشكل انتهازي بعد إنشاء العنصر.
- تُحذف العناصر منتهية الصلاحية.
- يزيل التنظيف الاحتياطي المجلدات القديمة الأثر الأقدم من 24 ساعة عندما تكون البيانات الوصفية مفقودة.
عنوان URL للعارض وسلوك الشبكة
مسار العارض:/plugins/diffs/view/{artifactId}/{token}
/plugins/diffs/assets/viewer.js/plugins/diffs/assets/viewer-runtime.js
baseUrl في طلبات الأصول.
سلوك بناء عنوان URL:
- إذا جرى توفير
baseUrlفي استدعاء الأداة، فسيُستخدَم بعد تحقق صارم. - وإلا إذا كان
viewerBaseUrlالخاص بـ plugin مضبوطًا، فسيُستخدَم. - من دون أي تجاوز، تكون القيمة الافتراضية لعنوان URL للعارض هي loopback
127.0.0.1. - إذا كان وضع ربط Gateway هو
customوكانgateway.customBindHostمضبوطًا، فسيُستخدَم ذلك المضيف.
baseUrl:
- يجب أن يبدأ بـ
http://أوhttps://. - يتم رفض query وhash.
- يُسمح بالأصل مع مسار أساسي اختياري.
نموذج الأمان
تقوية العارض:- loopback فقط افتراضيًا.
- مسارات عارض مميّزة برمز مع تحقق صارم من المعرّف والرمز المميز.
- سياسة CSP لاستجابة العارض:
default-src 'none'- السكربتات والأصول من self فقط
- لا يوجد
connect-srcصادر
- تقييد محاولات الفشل البعيدة عند تفعيل الوصول البعيد:
- 40 فشلًا لكل 60 ثانية
- حظر لمدة 60 ثانية (
429 Too Many Requests)
- توجيه طلبات متصفح لقطات الشاشة مُعطَّل افتراضيًا ما لم يُسمح به صراحةً.
- يُسمح فقط بأصول العارض المحلية من
http://127.0.0.1/plugins/diffs/assets/*. - تُحظر طلبات الشبكة الخارجية.
متطلبات المتصفح لوضع الملف
يحتاجmode: "file" وmode: "both" إلى متصفح متوافق مع Chromium.
ترتيب التحليل:
browser.executablePathفي تكوين OpenClaw.- متغيرات البيئة:
OPENCLAW_BROWSER_EXECUTABLE_PATHBROWSER_EXECUTABLE_PATHPLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH
- الرجوع إلى آلية اكتشاف أوامر/مسارات المنصة.
Diff PNG/PDF rendering requires a Chromium-compatible browser...
استكشاف الأخطاء وإصلاحها
أخطاء التحقق من الإدخال:Provide patch or both before and after text.- أدرج كلًا من
beforeوafter، أو وفّرpatch.
- أدرج كلًا من
Provide either patch or before/after input, not both.- لا تخلط بين أوضاع الإدخال.
Invalid baseUrl: ...- استخدم أصل
http(s)مع مسار اختياري، ومن دون query/hash.
- استخدم أصل
{field} exceeds maximum size (...)- قلّل حجم الحمولة.
- رفض patch كبير
- قلّل عدد ملفات patch أو إجمالي الأسطر.
- يُحل عنوان URL للعارض إلى
127.0.0.1افتراضيًا. - في سيناريوهات الوصول البعيد، إمّا:
- اضبط
viewerBaseUrlالخاص بـ plugin، أو - مرّر
baseUrlلكل استدعاء أداة، أو - استخدم
gateway.bind=customوgateway.customBindHost
- اضبط
- إذا كان
gateway.trustedProxiesيتضمن loopback لبروكسي على المضيف نفسه (مثل Tailscale Serve)، فإن طلبات العارض الخام عبر loopback من دون رؤوس forwarded client-IP تفشل بشكل مغلق حسب التصميم. - بالنسبة إلى هذه البنية للبروكسي:
- يُفضّل
mode: "file"أوmode: "both"عندما تحتاج فقط إلى مرفق، أو - فعّل
security.allowRemoteViewerعمدًا واضبطviewerBaseUrlالخاص بـ plugin أو مرّرbaseUrlللبروكسي/العامة عندما تحتاج إلى عنوان URL قابل للمشاركة للعارض
- يُفضّل
- فعّل
security.allowRemoteViewerفقط عندما تقصد تمكين وصول خارجي إلى العارض.
- قد يحدث هذا مع مدخلات patch عندما لا يحمل patch سياقًا قابلًا للتوسيع.
- هذا متوقع ولا يدل على فشل في العارض.
- انتهت صلاحية العنصر بسبب TTL.
- تغيّر الرمز المميز أو المسار.
- أزال التنظيف البيانات القديمة.
إرشادات التشغيل
- يُفضّل
mode: "view"للمراجعات التفاعلية المحلية داخل canvas. - يُفضّل
mode: "file"لقنوات الدردشة الصادرة التي تحتاج إلى مرفق. - أبقِ
allowRemoteViewerمعطّلًا ما لم يتطلب نشرُك عناوين URL بعيدة للعارض. - اضبط
ttlSecondsقصيرة وصريحة للفروق الحساسة. - تجنب إرسال الأسرار ضمن إدخال diff عندما لا يكون ذلك مطلوبًا.
- إذا كانت قناتك تضغط الصور بقوة (مثل Telegram أو WhatsApp)، ففضّل إخراج PDF (
fileFormat: "pdf").
- يعمل بواسطة Diffs.