Tools
ความแตกต่าง
diffs เป็นเครื่องมือ Plugin แบบไม่บังคับ พร้อมคำแนะนำระบบในตัวแบบสั้น และ Skill คู่กันที่เปลี่ยนเนื้อหาการเปลี่ยนแปลงให้เป็นอาร์ติแฟกต์ diff แบบอ่านอย่างเดียวสำหรับเอเจนต์
รองรับอินพุตได้ทั้ง:
- ข้อความ
beforeและafter patchแบบ unified
สามารถส่งคืนได้:
- URL ตัวแสดงผลของ Gateway สำหรับการนำเสนอผ่าน canvas
- พาธไฟล์ที่เรนเดอร์แล้ว (PNG หรือ PDF) สำหรับการส่งผ่านข้อความ
- เอาต์พุตทั้งสองแบบในการเรียกครั้งเดียว
เมื่อเปิดใช้งาน Plugin จะเพิ่มคำแนะนำการใช้งานแบบกระชับไว้ในพื้นที่ system-prompt และยังเปิดเผย Skill แบบละเอียดสำหรับกรณีที่เอเจนต์ต้องการคำแนะนำที่ครบถ้วนกว่า
เริ่มต้นอย่างรวดเร็ว
ติดตั้ง Plugin
openclaw plugins install diffs
เปิดใช้งาน Plugin
{
plugins: {
entries: {
diffs: {
enabled: true,
},
},
},
}
เลือกโหมด
view
โฟลว์ที่เน้น canvas เป็นหลัก: เอเจนต์เรียก diffs ด้วย mode: "view" และเปิด details.viewerUrl ด้วย canvas present
file
การส่งไฟล์ผ่านแชต: เอเจนต์เรียก diffs ด้วย mode: "file" และส่ง details.filePath ด้วย message โดยใช้ path หรือ filePath
both
แบบรวม: เอเจนต์เรียก diffs ด้วย mode: "both" เพื่อรับอาร์ติแฟกต์ทั้งสองแบบในการเรียกครั้งเดียว
ปิดใช้งานคำแนะนำระบบในตัว
หากต้องการเปิดใช้เครื่องมือ diffs ต่อไป แต่ปิดคำแนะนำ system-prompt ในตัว ให้ตั้งค่า plugins.entries.diffs.hooks.allowPromptInjection เป็น false:
{
plugins: {
entries: {
diffs: {
enabled: true,
hooks: {
allowPromptInjection: false,
},
},
},
},
}
การตั้งค่านี้บล็อก hook before_prompt_build ของ Plugin diffs ขณะที่ยังคงให้ Plugin, เครื่องมือ และ Skill คู่กันพร้อมใช้งาน
หากต้องการปิดทั้งคำแนะนำและเครื่องมือ ให้ปิดใช้งาน Plugin แทน
เวิร์กโฟลว์เอเจนต์ทั่วไป
เรียก diffs
เอเจนต์เรียกเครื่องมือ 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"
}
ข้อมูลอ้างอิงอินพุตของเครื่องมือ
ทุกฟิลด์เป็นแบบไม่บังคับ เว้นแต่จะระบุไว้
beforestringข้อความต้นฉบับ ต้องระบุพร้อม after เมื่อไม่ได้ระบุ patch
afterstringข้อความที่อัปเดต ต้องระบุพร้อม before เมื่อไม่ได้ระบุ patch
patchstringข้อความ unified diff ใช้ร่วมกับ before และ after ไม่ได้
pathstringชื่อไฟล์ที่แสดงสำหรับโหมดก่อนและหลัง
langstringคำใบ้สำหรับแทนที่ภาษาในโหมดก่อนและหลัง ค่าที่ไม่รู้จักจะย้อนกลับไปใช้ข้อความธรรมดา
titlestringการแทนที่ชื่อเรื่องของตัวแสดงผล
mode"view" | "file" | "both"โหมดเอาต์พุต ค่าเริ่มต้นคือค่าเริ่มต้นของ Plugin defaults.mode ชื่อแทนที่เลิกใช้แล้ว: "image" ทำงานเหมือน "file" และยังยอมรับอยู่เพื่อความเข้ากันได้ย้อนหลัง
theme"light" | "dark"ธีมของตัวแสดงผล ค่าเริ่มต้นคือค่าเริ่มต้นของ Plugin defaults.theme
layout"unified" | "split"เลย์เอาต์ diff ค่าเริ่มต้นคือค่าเริ่มต้นของ Plugin defaults.layout
expandUnchangedbooleanขยายส่วนที่ไม่เปลี่ยนแปลงเมื่อมีบริบทเต็มให้ใช้ได้ ตัวเลือกเฉพาะการเรียกเท่านั้น (ไม่ใช่คีย์ค่าเริ่มต้นของ Plugin)
fileFormat"png" | "pdf"รูปแบบไฟล์ที่เรนเดอร์ ค่าเริ่มต้นคือค่าเริ่มต้นของ Plugin defaults.fileFormat
fileQuality"standard" | "hq" | "print"พรีเซ็ตคุณภาพสำหรับการเรนเดอร์ PNG หรือ PDF
fileScalenumberการแทนที่สเกลอุปกรณ์ (1-4)
fileMaxWidthnumberความกว้างสูงสุดในการเรนเดอร์เป็นพิกเซล CSS (640-2400)
ttlSecondsnumberTTL ของอาร์ติแฟกต์เป็นวินาทีสำหรับเอาต์พุตตัวแสดงผลและไฟล์แบบสแตนด์อโลน สูงสุด 21600
baseUrlstringการแทนที่ origin ของ URL ตัวแสดงผล แทนที่ค่า Plugin viewerBaseUrl ต้องเป็น http หรือ https ไม่มี query/hash
ชื่อแทนอินพุตเดิม
ยังยอมรับอยู่เพื่อความเข้ากันได้ย้อนหลัง:
format->fileFormatimageFormat->fileFormatimageQuality->fileQualityimageScale->fileScaleimageMaxWidth->fileMaxWidth
การตรวจสอบความถูกต้องและขีดจำกัด
beforeและafterแต่ละรายการสูงสุด 512 KiBpatchสูงสุด 2 MiBpathสูงสุด 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)
สรุปพฤติกรรมของโหมด:
| โหมด | สิ่งที่ส่งคืน |
|---|---|
"view" |
ฟิลด์ตัวแสดงผลเท่านั้น |
"file" |
ฟิลด์ไฟล์เท่านั้น ไม่มีอาร์ติแฟกต์ตัวแสดงผล |
"both" |
ฟิลด์ตัวแสดงผลพร้อมฟิลด์ไฟล์ หากการเรนเดอร์ไฟล์ล้มเหลว ตัวแสดงผลยังคงส่งคืนพร้อมชื่อแทน fileError และ imageError |
ส่วนที่ไม่เปลี่ยนแปลงแบบยุบไว้
- ตัวแสดงผลสามารถแสดงแถวอย่าง
N unmodified lines - ปุ่มควบคุมการขยายในแถวเหล่านั้นเป็นแบบมีเงื่อนไข และไม่รับประกันว่าจะมีสำหรับอินพุตทุกชนิด
- ปุ่มควบคุมการขยายจะปรากฏเมื่อ diff ที่เรนเดอร์มีข้อมูลบริบทที่ขยายได้ ซึ่งพบได้ทั่วไปสำหรับอินพุตก่อนและหลัง
- สำหรับอินพุต unified patch จำนวนมาก เนื้อหาบริบทที่ละไว้ไม่มีอยู่ใน patch hunks ที่แยกวิเคราะห์แล้ว ดังนั้นแถวอาจปรากฏโดยไม่มีปุ่มควบคุมการขยาย นี่เป็นพฤติกรรมที่คาดไว้
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 ตัวแสดงผลแบบถาวร
viewerBaseUrlstringค่าทางเลือกสำรองที่ Plugin เป็นเจ้าของสำหรับลิงก์ตัวแสดงผลที่ส่งคืนเมื่อการเรียกเครื่องมือไม่ได้ส่ง baseUrl ต้องเป็น http หรือ https ไม่มี query/hash
{
plugins: {
entries: {
diffs: {
enabled: true,
config: {
viewerBaseUrl: "https://gateway.example.com/openclaw",
},
},
},
},
}
การกำหนดค่าความปลอดภัย
security.allowRemoteViewerbooleanfalse: คำขอที่ไม่ใช่ loopback ไปยังเส้นทางตัวแสดงผลจะถูกปฏิเสธ true: อนุญาตตัวแสดงผลระยะไกลหากพาธที่มีโทเค็นถูกต้อง
{
plugins: {
entries: {
diffs: {
enabled: true,
config: {
security: {
allowRemoteViewer: false,
},
},
},
},
},
}
วงจรชีวิตและที่จัดเก็บอาร์ติแฟกต์
- อาร์ติแฟกต์ถูกเก็บไว้ภายใต้โฟลเดอร์ย่อยชั่วคราว:
$TMPDIR/openclaw-diffs - เมตาดาต้าอาร์ติแฟกต์ของตัวแสดงผลประกอบด้วย:
- ID อาร์ติแฟกต์แบบสุ่ม (20 อักขระ hex)
- โทเค็นแบบสุ่ม (48 อักขระ hex)
createdAtและexpiresAt- พาธ
viewer.htmlที่จัดเก็บไว้
- TTL อาร์ติแฟกต์เริ่มต้นคือ 30 นาทีเมื่อไม่ได้ระบุ
- TTL ตัวแสดงผลสูงสุดที่ยอมรับคือ 6 ชั่วโมง
- การล้างข้อมูลทำงานแบบตามโอกาสหลังสร้างอาร์ติแฟกต์
- อาร์ติแฟกต์ที่หมดอายุจะถูกลบ
- การล้างข้อมูลสำรองจะลบโฟลเดอร์เก่าที่มีอายุมากกว่า 24 ชั่วโมงเมื่อเมตาดาต้าหายไป
URL ตัวแสดงผลและพฤติกรรมเครือข่าย
เส้นทางตัวแสดงผล:
/plugins/diffs/view/{artifactId}/{token}
แอสเซ็ตตัวแสดงผล:
/plugins/diffs/assets/viewer.js/plugins/diffs/assets/viewer-runtime.js
เอกสารตัวแสดงผลจะ resolve แอสเซ็ตเหล่านั้นโดยอิงจาก URL ตัวแสดงผล ดังนั้นคำนำหน้าพาธ baseUrl แบบไม่บังคับจึงถูกคงไว้สำหรับคำขอแอสเซ็ตทั้งสองด้วย
พฤติกรรมการสร้าง URL:
- หากระบุ
baseUrlในการเรียกเครื่องมือ จะใช้ค่านั้นหลังผ่านการตรวจสอบอย่างเข้มงวด - มิฉะนั้น หากกำหนดค่า
viewerBaseUrlของ Plugin ไว้ จะใช้ค่านั้น - หากไม่มีการแทนที่ทั้งสองแบบ URL ตัวแสดงผลจะใช้ค่าเริ่มต้นเป็น loopback
127.0.0.1 - หากโหมด bind ของ Gateway เป็น
customและตั้งค่าgateway.customBindHostไว้ จะใช้โฮสต์นั้น
กฎของ baseUrl:
- ต้องเป็น
http://หรือhttps:// - Query และ hash จะถูกปฏิเสธ
- อนุญาต origin พร้อมพาธฐานแบบไม่บังคับ
โมเดลความปลอดภัย
การเสริมความปลอดภัยของ Viewer
- ค่าเริ่มต้นจำกัดเฉพาะลูปแบ็กเท่านั้น
- เส้นทาง Viewer แบบมีโทเค็น พร้อมการตรวจสอบ ID และโทเค็นอย่างเข้มงวด
- CSP การตอบกลับของ Viewer:
default-src 'none'- สคริปต์และแอสเซตจากต้นทางเดียวกันเท่านั้น
- ไม่มี
connect-srcขาออก
- จำกัดอัตราเมื่อไม่พบปลายทางระยะไกล หากเปิดใช้งานการเข้าถึงระยะไกล:
- ล้มเหลว 40 ครั้งต่อ 60 วินาที
- ล็อกเอาต์ 60 วินาที (
429 Too Many Requests)
การเสริมความปลอดภัยของการเรนเดอร์ไฟล์
- การกำหนดเส้นทางคำขอเบราว์เซอร์สำหรับสกรีนช็อตเป็นแบบปฏิเสธโดยค่าเริ่มต้น
- อนุญาตเฉพาะแอสเซต Viewer ภายในเครื่องจาก
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หรือระบุpatchProvide either patch or before/after input, not both.— อย่าผสมโหมดอินพุตInvalid baseUrl: ...— ใช้ origin แบบhttp(s)พร้อมเส้นทางที่เป็นทางเลือกได้ ไม่มี query/hash{field} exceeds maximum size (...)— ลดขนาด payload- การปฏิเสธแพตช์ขนาดใหญ่ — ลดจำนวนไฟล์แพตช์หรือจำนวนบรรทัดทั้งหมด
การเข้าถึง Viewer
- URL ของ Viewer จะ resolve เป็น
127.0.0.1โดยค่าเริ่มต้น - สำหรับสถานการณ์การเข้าถึงระยะไกล ให้ทำอย่างใดอย่างหนึ่ง:
- ตั้งค่า
viewerBaseUrlของ Plugin หรือ - ส่ง
baseUrlในแต่ละการเรียกเครื่องมือ หรือ - ใช้
gateway.bind=customและgateway.customBindHost
- ตั้งค่า
- หาก
gateway.trustedProxiesรวมลูปแบ็กสำหรับพร็อกซีบนโฮสต์เดียวกัน (เช่น Tailscale Serve) คำขอ Viewer แบบลูปแบ็กดิบที่ไม่มีส่วนหัว client-IP ที่ส่งต่อมาจะล้มเหลวแบบปิดตามการออกแบบ - สำหรับโทโพโลยีพร็อกซีนี้:
- แนะนำให้ใช้
mode: "file"หรือmode: "both"เมื่อคุณต้องการเพียงไฟล์แนบ หรือ - ตั้งใจเปิดใช้
security.allowRemoteViewerและตั้งค่าviewerBaseUrlของ Plugin หรือส่งbaseUrlของพร็อกซี/สาธารณะ เมื่อคุณต้องการ URL ของ Viewer ที่แชร์ได้
- แนะนำให้ใช้
- เปิดใช้
security.allowRemoteViewerเฉพาะเมื่อคุณต้องการให้เข้าถึง Viewer จากภายนอก
แถวบรรทัดที่ไม่ได้แก้ไขไม่มีปุ่มขยาย
กรณีนี้อาจเกิดขึ้นกับอินพุตแพตช์เมื่อแพตช์ไม่มีบริบทที่ขยายได้ นี่เป็นพฤติกรรมที่คาดไว้และไม่ได้บ่งชี้ว่า Viewer ล้มเหลว
ไม่พบอาร์ติแฟกต์
- อาร์ติแฟกต์หมดอายุเนื่องจาก TTL
- โทเค็นหรือเส้นทางเปลี่ยนไป
- การล้างข้อมูลลบข้อมูลเก่าที่ค้างไว้
คำแนะนำด้านการปฏิบัติงาน
- แนะนำให้ใช้
mode: "view"สำหรับการรีวิวแบบโต้ตอบภายในเครื่องในแคนวาส - แนะนำให้ใช้
mode: "file"สำหรับช่องทางแชตขาออกที่ต้องใช้ไฟล์แนบ - ปิดใช้งาน
allowRemoteViewerไว้ เว้นแต่ว่าการปรับใช้ของคุณต้องใช้ URL ของ Viewer ระยะไกล - ตั้งค่า
ttlSecondsให้สั้นอย่างชัดเจนสำหรับ diff ที่มีความอ่อนไหว - หลีกเลี่ยงการส่งความลับในอินพุต diff เมื่อไม่จำเป็น
- หากช่องทางของคุณบีบอัดรูปภาพอย่างหนัก (เช่น Telegram หรือ WhatsApp) แนะนำให้ใช้เอาต์พุต PDF (
fileFormat: "pdf")