18 KiB
| read_when | summary | title | x-i18n | |||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
عارض فروق للقراءة فقط ومُصيِّر ملفات للوكلاء (أداة plugin اختيارية) | الفروق |
|
الفروق
diffs هي أداة plugin اختيارية تحتوي على إرشادات نظام مضمّنة قصيرة ومهارة مصاحبة تحوّل محتوى التغييرات إلى عنصر فروق للقراءة فقط للوكلاء.
تقبل أحد الخيارين التاليين:
- النص
beforeوafter patchموحّد
ويمكنها إرجاع:
- عنوان URL لعارض البوابة لعرضه في canvas
- مسار ملف مُصيَّر (PNG أو PDF) لتسليم الرسائل
- كلا المخرجين في استدعاء واحد
عند تفعيلها، تضيف plugin إرشادات استخدام موجزة إلى مساحة system-prompt، كما تكشف أيضًا عن مهارة مفصلة للحالات التي يحتاج فيها الوكيل إلى تعليمات أكثر اكتمالًا.
بداية سريعة
- فعّل plugin.
- استدعِ
diffsباستخدامmode: "view"للتدفقات التي يكون فيها canvas أولًا. - استدعِ
diffsباستخدامmode: "file"لتدفقات تسليم الملفات في الدردشة. - استدعِ
diffsباستخدامmode: "both"عندما تحتاج إلى كلا العنصرين.
تفعيل plugin
{
plugins: {
entries: {
diffs: {
enabled: true,
},
},
},
}
تعطيل إرشادات النظام المضمّنة
إذا كنت تريد إبقاء أداة diffs مفعلة مع تعطيل إرشاداتها المضمّنة في system-prompt، فاضبط plugins.entries.diffs.hooks.allowPromptInjection على false:
{
plugins: {
entries: {
diffs: {
enabled: true,
hooks: {
allowPromptInjection: false,
},
},
},
},
}
يمنع هذا hook الخاص بـ before_prompt_build في plugin الفروق مع الإبقاء على plugin والأداة والمهارة المصاحبة متاحة.
إذا كنت تريد تعطيل كل من الإرشادات والأداة، فعطّل plugin بدلًا من ذلك.
سير عمل الوكيل المعتاد
- يستدعي الوكيل
diffs. - يقرأ الوكيل حقول
details. - ثم يقوم الوكيل بأحد ما يلي:
- يفتح
details.viewerUrlباستخدامcanvas present - يرسل
details.filePathباستخدامmessageمعpathأوfilePath - أو يفعل الأمرين معًا
- يفتح
أمثلة الإدخال
قبل وبعد:
{
"before": "# Hello\n\nOne",
"after": "# Hello\n\nTwo",
"path": "docs/example.md",
"mode": "view"
}
Patch:
{
"patch": "diff --git a/src/example.ts b/src/example.ts\n--- a/src/example.ts\n+++ b/src/example.ts\n@@ -1 +1 @@\n-const x = 1;\n+const x = 2;\n",
"mode": "both"
}
مرجع مُدخلات الأداة
كل الحقول اختيارية ما لم يُذكر خلاف ذلك:
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عند التوفر)
حقول الملفات عند تصيير PNG أو PDF:
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:
{
plugins: {
entries: {
diffs: {
enabled: true,
config: {
defaults: {
fontFamily: "Fira Code",
fontSize: 15,
lineSpacing: 1.6,
layout: "unified",
showLineNumbers: true,
diffIndicators: "bars",
wordWrap: true,
background: true,
theme: "dark",
fileFormat: "png",
fileQuality: "standard",
fileScale: 2,
fileMaxWidth: 960,
mode: "both",
},
},
},
},
},
}
القيم الافتراضية المدعومة:
fontFamilyfontSizelineSpacinglayoutshowLineNumbersdiffIndicatorswordWrapbackgroundthemefileFormatfileQualityfileScalefileMaxWidthmode
تتجاوز معلمات الأداة الصريحة هذه القيم الافتراضية.
إعداد عنوان URL الدائم للعارض:
viewerBaseUrl(string، اختياري)- بديل مملوك للـ plugin للروابط المعادة الخاصة بالعارض عندما لا يمرر استدعاء الأداة
baseUrl. - يجب أن يكون
httpأوhttps، ومن دون query/hash.
- بديل مملوك للـ plugin للروابط المعادة الخاصة بالعارض عندما لا يمرر استدعاء الأداة
مثال:
{
plugins: {
entries: {
diffs: {
enabled: true,
config: {
viewerBaseUrl: "https://gateway.example.com/openclaw",
},
},
},
},
}
إعدادات الأمان
security.allowRemoteViewer(boolean، الافتراضيfalse)false: تُرفَض الطلبات غير القادمة من loopback إلى مسارات العارض.true: يُسمح بالعارضات البعيدة إذا كان المسار المرمّز صالحًا.
مثال:
{
plugins: {
entries: {
diffs: {
enabled: true,
config: {
security: {
allowRemoteViewer: false,
},
},
},
},
},
}
دورة حياة العناصر والتخزين
- تُخزَّن العناصر ضمن المجلد الفرعي المؤقت:
$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
يحل مستند العارض هذه الأصول نسبةً إلى عنوان URL الخاص بالعارض، لذلك يُحفَظ أيضًا أي بادئة مسار اختيارية لـ 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...
يمكن إصلاح ذلك بتثبيت Chrome أو Chromium أو Edge أو Brave، أو بضبط أحد خيارات مسار الملف التنفيذي أعلاه.
استكشاف الأخطاء وإصلاحها
أخطاء التحقق من الإدخال:
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.