diff --git a/docs/th/channels/discord.md b/docs/th/channels/discord.md index 50c9cc80e..453be407b 100644 --- a/docs/th/channels/discord.md +++ b/docs/th/channels/discord.md @@ -1,18 +1,18 @@ --- read_when: - - กำลังทำงานกับฟีเจอร์ช่องทาง Discord + - การทำงานกับฟีเจอร์ช่องทาง Discord summary: สถานะการรองรับบอต Discord ความสามารถ และการกำหนดค่า title: Discord x-i18n: - generated_at: "2026-05-04T02:21:27Z" + generated_at: "2026-05-04T07:02:50Z" model: gpt-5.5 provider: openai - source_hash: df4e045e39f8977f779fe409abf41dad0d950c92f1230c51ff356343513df812 + source_hash: 1e00f9d9b134296ac1ca52bb4058fc62ea7a95c4d46d9478648b2ecdd448652a source_path: channels/discord.md workflow: 16 --- -พร้อมสำหรับ DM และช่องกิลด์ผ่าน Discord gateway อย่างเป็นทางการ +พร้อมสำหรับ DM และช่องกิลด์ผ่าน Gateway ทางการของ Discord @@ -21,29 +21,29 @@ x-i18n: พฤติกรรมคำสั่งแบบเนทีฟและแคตตาล็อกคำสั่ง - - การวินิจฉัยข้ามช่องทางและโฟลว์การซ่อมแซม + + การวินิจฉัยข้ามช่องและขั้นตอนการซ่อมแซม -## การตั้งค่าอย่างรวดเร็ว +## การตั้งค่าแบบเร็ว -คุณจะต้องสร้างแอปพลิเคชันใหม่พร้อมบอต เพิ่มบอตไปยังเซิร์ฟเวอร์ของคุณ และจับคู่กับ OpenClaw เราแนะนำให้เพิ่มบอตของคุณไปยังเซิร์ฟเวอร์ส่วนตัวของคุณเอง หากคุณยังไม่มี [ให้สร้างก่อน](https://support.discord.com/hc/en-us/articles/204849977-How-do-I-create-a-server) (เลือก **Create My Own > For me and my friends**) +คุณจะต้องสร้างแอปพลิเคชันใหม่พร้อมบอต เพิ่มบอตลงในเซิร์ฟเวอร์ของคุณ และจับคู่กับ OpenClaw เราแนะนำให้เพิ่มบอตของคุณลงในเซิร์ฟเวอร์ส่วนตัวของคุณเอง หากคุณยังไม่มี ให้[สร้างก่อน](https://support.discord.com/hc/en-us/articles/204849977-How-do-I-create-a-server) (เลือก **Create My Own > For me and my friends**) - ไปที่ [Discord Developer Portal](https://discord.com/developers/applications) แล้วคลิก **New Application** ตั้งชื่อเป็นอย่างเช่น "OpenClaw" + ไปที่ [Discord Developer Portal](https://discord.com/developers/applications) แล้วคลิก **New Application** ตั้งชื่อเช่น "OpenClaw" - คลิก **Bot** บนแถบด้านข้าง ตั้งค่า **Username** เป็นชื่อที่คุณใช้เรียกเอเจนต์ OpenClaw ของคุณ + คลิก **Bot** บนแถบด้านข้าง ตั้งค่า **Username** เป็นชื่อใดก็ได้ที่คุณใช้เรียกเอเจนต์ OpenClaw ของคุณ - ยังคงอยู่บนหน้า **Bot** เลื่อนลงไปที่ **Privileged Gateway Intents** แล้วเปิดใช้งาน: + ยังอยู่บนหน้า **Bot** ให้เลื่อนลงไปที่ **Privileged Gateway Intents** แล้วเปิดใช้งาน: - **Message Content Intent** (จำเป็น) - - **Server Members Intent** (แนะนำ; จำเป็นสำหรับรายการอนุญาตตามบทบาทและการจับคู่ชื่อกับ ID) - - **Presence Intent** (ไม่บังคับ; ต้องใช้เฉพาะสำหรับการอัปเดต presence) + - **Server Members Intent** (แนะนำ; จำเป็นสำหรับ allowlist ตามบทบาทและการจับคู่ชื่อกับ ID) + - **Presence Intent** (ไม่บังคับ; จำเป็นเฉพาะสำหรับการอัปเดต presence) @@ -51,15 +51,15 @@ x-i18n: เลื่อนกลับขึ้นไปบนหน้า **Bot** แล้วคลิก **Reset Token** - แม้ชื่อจะเป็นเช่นนั้น แต่สิ่งนี้จะสร้างโทเค็นแรกของคุณ ไม่มีสิ่งใดถูก "รีเซ็ต" + แม้ชื่อจะเป็นเช่นนั้น แต่นี่คือการสร้างโทเค็นแรกของคุณ — ไม่มีสิ่งใดถูก "รีเซ็ต" - คัดลอกโทเค็นแล้วบันทึกไว้ที่ใดที่หนึ่ง นี่คือ **Bot Token** ของคุณ และคุณจะต้องใช้ในไม่ช้า + คัดลอกโทเค็นและบันทึกไว้ที่ใดที่หนึ่ง นี่คือ **Bot Token** ของคุณ และคุณจะต้องใช้ในอีกไม่นาน - - คลิก **OAuth2** บนแถบด้านข้าง คุณจะสร้าง URL คำเชิญที่มีสิทธิ์ที่ถูกต้องเพื่อเพิ่มบอตไปยังเซิร์ฟเวอร์ของคุณ + + คลิก **OAuth2** บนแถบด้านข้าง คุณจะสร้าง URL คำเชิญพร้อมสิทธิ์ที่ถูกต้องเพื่อเพิ่มบอตลงในเซิร์ฟเวอร์ของคุณ เลื่อนลงไปที่ **OAuth2 URL Generator** แล้วเปิดใช้งาน: @@ -68,40 +68,40 @@ x-i18n: ส่วน **Bot Permissions** จะปรากฏด้านล่าง เปิดใช้งานอย่างน้อย: - **สิทธิ์ทั่วไป** - - ดูช่อง - **สิทธิ์ข้อความ** - - ส่งข้อความ - - อ่านประวัติข้อความ - - ฝังลิงก์ - - แนบไฟล์ - - เพิ่มรีแอ็กชัน (ไม่บังคับ) + **General Permissions** + - View Channels + **Text Permissions** + - Send Messages + - Read Message History + - Embed Links + - Attach Files + - Add Reactions (ไม่บังคับ) - นี่คือชุดพื้นฐานสำหรับช่องข้อความปกติ หากคุณวางแผนจะโพสต์ในเธรดของ Discord รวมถึงเวิร์กโฟลว์ช่องฟอรัมหรือสื่อที่สร้างหรือดำเนินเธรดต่อ ให้เปิดใช้งาน **Send Messages in Threads** ด้วย - คัดลอก URL ที่สร้างขึ้นที่ด้านล่าง วางลงในเบราว์เซอร์ของคุณ เลือกเซิร์ฟเวอร์ของคุณ แล้วคลิก **Continue** เพื่อเชื่อมต่อ ตอนนี้คุณควรเห็นบอตของคุณในเซิร์ฟเวอร์ Discord แล้ว + นี่คือชุดพื้นฐานสำหรับช่องข้อความปกติ หากคุณวางแผนจะโพสต์ในเธรด Discord รวมถึงเวิร์กโฟลว์ช่อง forum หรือ media ที่สร้างหรือดำเนินเธรดต่อ ให้เปิดใช้งาน **Send Messages in Threads** ด้วย + คัดลอก URL ที่สร้างไว้ด้านล่าง วางในเบราว์เซอร์ของคุณ เลือกเซิร์ฟเวอร์ของคุณ แล้วคลิก **Continue** เพื่อเชื่อมต่อ ตอนนี้คุณควรเห็นบอตของคุณในเซิร์ฟเวอร์ Discord แล้ว - + กลับไปที่แอป Discord คุณต้องเปิดใช้งาน Developer Mode เพื่อให้คัดลอก ID ภายในได้ - 1. คลิก **User Settings** (ไอคอนเฟืองถัดจากอวาตาร์ของคุณ) → **Advanced** → เปิดสวิตช์ **Developer Mode** - 2. คลิกขวาที่ **ไอคอนเซิร์ฟเวอร์** ของคุณในแถบด้านข้าง → **Copy Server ID** - 3. คลิกขวาที่ **อวาตาร์ของคุณเอง** → **Copy User ID** + 1. คลิก **User Settings** (ไอคอนเฟืองถัดจากรูปโปรไฟล์ของคุณ) → **Advanced** → เปิด **Developer Mode** + 2. คลิกขวาที่ **server icon** ของคุณในแถบด้านข้าง → **Copy Server ID** + 3. คลิกขวาที่ **own avatar** ของคุณ → **Copy User ID** - บันทึก **Server ID** และ **User ID** ของคุณไว้ร่วมกับ Bot Token คุณจะส่งทั้งสามรายการให้ OpenClaw ในขั้นตอนถัดไป + บันทึก **Server ID** และ **User ID** ของคุณไว้คู่กับ Bot Token — คุณจะส่งทั้งสามอย่างไปยัง OpenClaw ในขั้นตอนถัดไป - เพื่อให้การจับคู่ทำงานได้ Discord ต้องอนุญาตให้บอตของคุณส่ง DM ถึงคุณ คลิกขวาที่ **ไอคอนเซิร์ฟเวอร์** ของคุณ → **Privacy Settings** → เปิดสวิตช์ **Direct Messages** + เพื่อให้การจับคู่ทำงาน Discord ต้องอนุญาตให้บอตของคุณส่ง DM ถึงคุณได้ คลิกขวาที่ **server icon** ของคุณ → **Privacy Settings** → เปิด **Direct Messages** - สิ่งนี้ทำให้สมาชิกเซิร์ฟเวอร์ (รวมถึงบอต) ส่ง DM ถึงคุณได้ เปิดใช้งานไว้หากคุณต้องการใช้ DM ของ Discord กับ OpenClaw หากคุณวางแผนจะใช้เฉพาะช่องกิลด์ คุณสามารถปิดใช้งาน DM หลังการจับคู่ได้ + การตั้งค่านี้ทำให้สมาชิกเซิร์ฟเวอร์ (รวมถึงบอต) ส่ง DM ถึงคุณได้ เปิดไว้ต่อไปหากคุณต้องการใช้ DM ของ Discord กับ OpenClaw หากคุณวางแผนจะใช้เฉพาะช่องกิลด์ คุณสามารถปิด DM หลังจากจับคู่แล้ว - - โทเค็นบอต Discord ของคุณเป็นความลับ (เหมือนรหัสผ่าน) ตั้งค่าบนเครื่องที่รัน OpenClaw ก่อนส่งข้อความถึงเอเจนต์ของคุณ + + โทเค็นบอต Discord ของคุณเป็นความลับ (เหมือนรหัสผ่าน) ตั้งค่าไว้บนเครื่องที่รัน OpenClaw ก่อนส่งข้อความถึงเอเจนต์ของคุณ ```bash export DISCORD_BOT_TOKEN="YOUR_BOT_TOKEN" @@ -120,9 +120,9 @@ openclaw config patch --file ./discord.patch.json5 openclaw gateway ``` - หาก OpenClaw กำลังรันเป็นบริการเบื้องหลังอยู่แล้ว ให้รีสตาร์ทผ่านแอป OpenClaw Mac หรือโดยหยุดและเริ่มกระบวนการ `openclaw gateway run` ใหม่ - สำหรับการติดตั้งบริการที่จัดการแล้ว ให้รัน `openclaw gateway install` จากเชลล์ที่มี `DISCORD_BOT_TOKEN` อยู่ หรือเก็บตัวแปรไว้ใน `~/.openclaw/.env` เพื่อให้บริการสามารถ resolve env SecretRef ได้หลังรีสตาร์ท - หากโฮสต์ของคุณถูกบล็อกหรือถูกจำกัดอัตราโดยการค้นหาแอปพลิเคชันของ Discord ตอนเริ่มต้น ให้ตั้งค่า ID แอปพลิเคชัน/ไคลเอนต์ Discord จาก Developer Portal เพื่อให้การเริ่มต้นข้าม REST call นั้นได้ ใช้ `channels.discord.applicationId` สำหรับบัญชีเริ่มต้น หรือ `channels.discord.accounts..applicationId` เมื่อคุณรันบอต Discord หลายตัว + หาก OpenClaw กำลังรันเป็นบริการเบื้องหลังอยู่แล้ว ให้รีสตาร์ทผ่านแอป OpenClaw Mac หรือหยุดแล้วเริ่มกระบวนการ `openclaw gateway run` ใหม่ + สำหรับการติดตั้งบริการที่จัดการไว้ ให้รัน `openclaw gateway install` จากเชลล์ที่มี `DISCORD_BOT_TOKEN` อยู่ หรือเก็บตัวแปรไว้ใน `~/.openclaw/.env` เพื่อให้บริการ resolve env SecretRef ได้หลังรีสตาร์ท + หากโฮสต์ของคุณถูกบล็อกหรือถูกจำกัดอัตราโดยการค้นหาแอปพลิเคชันตอนเริ่มต้นของ Discord ให้ตั้งค่า ID แอปพลิเคชัน/ไคลเอนต์ Discord จาก Developer Portal เพื่อให้การเริ่มต้นข้าม REST call นั้นได้ ใช้ `channels.discord.applicationId` สำหรับบัญชีค่าเริ่มต้น หรือ `channels.discord.accounts..applicationId` เมื่อคุณรันบอต Discord หลายตัว @@ -130,12 +130,12 @@ openclaw gateway - แชตกับเอเจนต์ OpenClaw ของคุณบนช่องทางที่มีอยู่ใดก็ได้ (เช่น Telegram) แล้วบอกเอเจนต์ หาก Discord เป็นช่องทางแรกของคุณ ให้ใช้แท็บ CLI / config แทน + แชตกับเอเจนต์ OpenClaw ของคุณบนช่องที่มีอยู่ใดก็ได้ (เช่น Telegram) แล้วบอกเอเจนต์ หาก Discord เป็นช่องแรกของคุณ ให้ใช้แท็บ CLI / config แทน > "ฉันตั้งค่าโทเค็นบอต Discord ใน config แล้ว โปรดตั้งค่า Discord ให้เสร็จด้วย User ID `` และ Server ID ``" - หากคุณต้องการ config แบบไฟล์ ให้ตั้งค่า: + หากคุณต้องการใช้ config แบบไฟล์ ให้ตั้งค่า: ```json5 { @@ -152,15 +152,15 @@ openclaw gateway } ``` - Env fallback สำหรับบัญชีเริ่มต้น: + Env fallback สำหรับบัญชีค่าเริ่มต้น: ```bash DISCORD_BOT_TOKEN=... ``` - สำหรับการตั้งค่าแบบสคริปต์หรือระยะไกล ให้เขียนบล็อก JSON5 เดียวกันด้วย `openclaw config patch --file ./discord.patch.json5 --dry-run` แล้วรันซ้ำโดยไม่มี `--dry-run` รองรับค่า `token` แบบ plaintext ค่า SecretRef ก็รองรับสำหรับ `channels.discord.token` ผ่านผู้ให้บริการ env/file/exec เช่นกัน ดู [การจัดการความลับ](/th/gateway/secrets) + สำหรับการตั้งค่าแบบสคริปต์หรือระยะไกล ให้เขียนบล็อก JSON5 เดียวกันด้วย `openclaw config patch --file ./discord.patch.json5 --dry-run` แล้วรันซ้ำโดยไม่มี `--dry-run` รองรับค่า `token` แบบ plaintext และรองรับค่า SecretRef สำหรับ `channels.discord.token` ผ่านผู้ให้บริการ env/file/exec ด้วย ดู [การจัดการ Secrets](/th/gateway/secrets) - สำหรับบอต Discord หลายตัว ให้เก็บโทเค็นบอตและ ID แอปพลิเคชันแต่ละตัวไว้ใต้บัญชีของมัน `channels.discord.applicationId` ระดับบนจะถูกสืบทอดโดยบัญชี ดังนั้นให้ตั้งค่าไว้ตรงนั้นเฉพาะเมื่อทุกบัญชีควรใช้ ID แอปพลิเคชันเดียวกัน + สำหรับบอต Discord หลายตัว ให้เก็บโทเค็นบอตและ ID แอปพลิเคชันแต่ละตัวไว้ใต้บัญชีของตัวเอง `channels.discord.applicationId` ระดับบนสุดจะถูกสืบทอดโดยบัญชีต่างๆ ดังนั้นให้ตั้งไว้ตรงนั้นเฉพาะเมื่อทุกบัญชีควรใช้ ID แอปพลิเคชันเดียวกัน ```json5 { @@ -188,13 +188,13 @@ DISCORD_BOT_TOKEN=... - รอจนกว่า gateway จะรันอยู่ จากนั้นส่ง DM ถึงบอตของคุณใน Discord บอตจะตอบกลับด้วยรหัสการจับคู่ + รอจนกว่า Gateway จะรันอยู่ แล้วส่ง DM ถึงบอตของคุณใน Discord บอตจะตอบกลับด้วยรหัสจับคู่ - ส่งรหัสการจับคู่ให้เอเจนต์ของคุณบนช่องทางที่มีอยู่: + ส่งรหัสจับคู่ไปยังเอเจนต์ของคุณบนช่องที่มีอยู่: - > "อนุมัติรหัสการจับคู่ Discord นี้: ``" + > "อนุมัติรหัสจับคู่ Discord นี้: ``" @@ -206,30 +206,30 @@ openclaw pairing approve discord - รหัสการจับคู่จะหมดอายุหลัง 1 ชั่วโมง + รหัสจับคู่หมดอายุหลังจาก 1 ชั่วโมง - ตอนนี้คุณควรสามารถแชตกับเอเจนต์ของคุณใน Discord ผ่าน DM ได้แล้ว + ตอนนี้คุณควรแชตกับเอเจนต์ของคุณใน Discord ผ่าน DM ได้แล้ว -การ resolve โทเค็นรับรู้ตามบัญชี ค่าโทเค็นใน config จะชนะ env fallback `DISCORD_BOT_TOKEN` ใช้เฉพาะสำหรับบัญชีเริ่มต้นเท่านั้น -หากบัญชี Discord ที่เปิดใช้งานสองบัญชี resolve ไปยังโทเค็นบอตเดียวกัน OpenClaw จะเริ่ม gateway monitor เพียงตัวเดียวสำหรับโทเค็นนั้น โทเค็นจาก config จะชนะ env fallback เริ่มต้น มิฉะนั้นบัญชีที่เปิดใช้งานบัญชีแรกจะชนะ และบัญชีที่ซ้ำจะถูกรายงานว่าปิดใช้งาน -สำหรับการเรียกขาออกขั้นสูง (เครื่องมือข้อความ/การทำงานของช่องทาง) จะใช้ `token` แบบระบุต่อการเรียกสำหรับการเรียกนั้น สิ่งนี้ใช้กับการทำงานแบบส่งและอ่าน/ตรวจสอบ (เช่น read/search/fetch/thread/pins/permissions) การตั้งค่านโยบายบัญชี/การลองซ้ำยังคงมาจากบัญชีที่เลือกใน snapshot รันไทม์ที่ใช้งานอยู่ +การ resolve โทเค็นรับรู้ตามบัญชี ค่าโทเค็นใน config มีลำดับความสำคัญเหนือ env fallback `DISCORD_BOT_TOKEN` ใช้เฉพาะกับบัญชีค่าเริ่มต้นเท่านั้น +หากบัญชี Discord ที่เปิดใช้งานสองบัญชี resolve เป็นโทเค็นบอตเดียวกัน OpenClaw จะเริ่ม gateway monitor เพียงหนึ่งตัวสำหรับโทเค็นนั้น โทเค็นจาก config มีลำดับความสำคัญเหนือ env fallback ค่าเริ่มต้น มิฉะนั้นบัญชีที่เปิดใช้งานบัญชีแรกจะมีลำดับความสำคัญ และบัญชีซ้ำจะถูกรายงานว่าปิดใช้งาน +สำหรับ outbound call ขั้นสูง (เครื่องมือ message/การดำเนินการ channel) จะใช้ `token` แบบระบุต่อ call สำหรับ call นั้น การตั้งค่านี้ใช้กับการส่งและการดำเนินการแบบอ่าน/probe (เช่น read/search/fetch/thread/pins/permissions) การตั้งค่านโยบายบัญชี/retry ยังคงมาจากบัญชีที่เลือกใน runtime snapshot ที่ใช้งานอยู่ -## แนะนำ: ตั้งค่าเวิร์กสเปซกิลด์ +## แนะนำ: ตั้งค่าพื้นที่ทำงานกิลด์ -เมื่อ DM ใช้งานได้แล้ว คุณสามารถตั้งค่าเซิร์ฟเวอร์ Discord ของคุณเป็นเวิร์กสเปซเต็มรูปแบบ โดยแต่ละช่องจะมีเซสชันเอเจนต์ของตัวเองพร้อมบริบทของตัวเอง วิธีนี้แนะนำสำหรับเซิร์ฟเวอร์ส่วนตัวที่มีเพียงคุณและบอตของคุณ +เมื่อ DM ทำงานแล้ว คุณสามารถตั้งค่าเซิร์ฟเวอร์ Discord ของคุณเป็นพื้นที่ทำงานเต็มรูปแบบที่แต่ละช่องมีเซสชันเอเจนต์ของตัวเองพร้อมบริบทของตัวเอง แนะนำสำหรับเซิร์ฟเวอร์ส่วนตัวที่มีแค่คุณและบอตของคุณ - - สิ่งนี้ทำให้เอเจนต์ของคุณตอบกลับในช่องใดก็ได้บนเซิร์ฟเวอร์ของคุณ ไม่ใช่แค่ DM + + การตั้งค่านี้ทำให้เอเจนต์ของคุณตอบสนองในช่องใดก็ได้บนเซิร์ฟเวอร์ของคุณ ไม่ใช่แค่ DM - > "เพิ่ม Discord Server ID `` ของฉันไปยังรายการอนุญาตของกิลด์" + > "เพิ่ม Discord Server ID `` ของฉันลงใน guild allowlist" @@ -254,16 +254,16 @@ openclaw pairing approve discord - - โดยค่าเริ่มต้น เอเจนต์ของคุณจะตอบกลับในช่องกิลด์เมื่อถูก @mention เท่านั้น สำหรับเซิร์ฟเวอร์ส่วนตัว คุณอาจต้องการให้ตอบกลับทุกข้อความ + + โดยค่าเริ่มต้น เอเจนต์ของคุณจะตอบสนองในช่องกิลด์เฉพาะเมื่อถูก @mention เท่านั้น สำหรับเซิร์ฟเวอร์ส่วนตัว คุณน่าจะต้องการให้ตอบทุกข้อความ - ในช่องกิลด์ คำตอบสุดท้ายปกติของผู้ช่วยจะยังคงเป็นส่วนตัวโดยค่าเริ่มต้น เอาต์พุต Discord ที่มองเห็นได้ต้องถูกส่งอย่างชัดเจนด้วยเครื่องมือ `message` ดังนั้นเอเจนต์จึงสามารถเฝ้าดูอยู่เบื้องหลังเป็นค่าเริ่มต้น และโพสต์เฉพาะเมื่อมันตัดสินว่าคำตอบในช่องมีประโยชน์ + ในช่องกิลด์ คำตอบสุดท้ายปกติของผู้ช่วยจะยังคงเป็นส่วนตัวโดยค่าเริ่มต้น เอาต์พุต Discord ที่มองเห็นได้ต้องถูกส่งอย่างชัดเจนด้วยเครื่องมือ `message` เพื่อให้เอเจนต์เฝ้าดูได้ตามค่าเริ่มต้นและโพสต์เฉพาะเมื่อเห็นว่าการตอบกลับในช่องมีประโยชน์ - ซึ่งหมายความว่าโมเดลที่เลือกต้องเรียกเครื่องมือได้อย่างเชื่อถือได้ หาก Discord แสดงว่ากำลังพิมพ์และบันทึกแสดงการใช้โทเค็นแต่ไม่มีข้อความที่โพสต์ ให้ตรวจสอบบันทึกเซสชันสำหรับข้อความผู้ช่วยที่มี `didSendViaMessagingTool: false` นั่นหมายความว่าโมเดลสร้างคำตอบสุดท้ายส่วนตัวแทนการเรียก `message(action=send)` เปลี่ยนไปใช้โมเดลที่เรียกเครื่องมือได้แข็งแรงกว่า หรือใช้ config ด้านล่างเพื่อคืนค่าคำตอบสุดท้ายอัตโนมัติแบบเดิม + ซึ่งหมายความว่าโมเดลที่เลือกต้องเรียกใช้เครื่องมือได้อย่างน่าเชื่อถือ หาก Discord แสดงว่ากำลังพิมพ์และบันทึกแสดงการใช้โทเค็นแต่ไม่มีข้อความที่โพสต์ ให้ตรวจบันทึกเซสชันสำหรับข้อความผู้ช่วยที่มี `didSendViaMessagingTool: false` นั่นหมายความว่าโมเดลสร้างคำตอบสุดท้ายแบบส่วนตัวแทนการเรียก `message(action=send)` ให้เปลี่ยนไปใช้โมเดลที่เรียกเครื่องมือได้ดีกว่า หรือใช้ config ด้านล่างเพื่อกู้คืนการตอบกลับสุดท้ายอัตโนมัติแบบเดิม - > "อนุญาตให้เอเจนต์ของฉันตอบกลับบนเซิร์ฟเวอร์นี้โดยไม่ต้องถูก @mentioned" + > "อนุญาตให้เอเจนต์ของฉันตอบสนองบนเซิร์ฟเวอร์นี้โดยไม่ต้องถูก @mentioned" ตั้งค่า `requireMention: false` ใน config กิลด์ของคุณ: @@ -282,7 +282,7 @@ openclaw pairing approve discord } ``` - หากต้องการคืนค่าคำตอบสุดท้ายอัตโนมัติแบบเดิมสำหรับห้องกลุ่ม/ช่อง ให้ตั้งค่า `messages.groupChat.visibleReplies: "automatic"` + หากต้องการกู้คืนการตอบกลับสุดท้ายอัตโนมัติแบบเดิมสำหรับห้องกลุ่ม/channel ให้ตั้งค่า `messages.groupChat.visibleReplies: "automatic"` @@ -290,83 +290,88 @@ openclaw pairing approve discord - โดยค่าเริ่มต้น หน่วยความจำระยะยาว (MEMORY.md) จะโหลดเฉพาะในเซสชัน DM ช่องกิลด์จะไม่โหลด MEMORY.md โดยอัตโนมัติ + โดยค่าเริ่มต้น หน่วยความจำระยะยาว (MEMORY.md) จะโหลดเฉพาะในเซสชัน DM ช่องกิลด์จะไม่โหลด MEMORY.md อัตโนมัติ > "เมื่อฉันถามคำถามในช่อง Discord ให้ใช้ memory_search หรือ memory_get หากคุณต้องการบริบทระยะยาวจาก MEMORY.md" - หากคุณต้องการบริบทที่ใช้ร่วมกันในทุกช่อง ให้วางคำสั่งที่คงที่ไว้ใน `AGENTS.md` หรือ `USER.md` (ไฟล์เหล่านี้จะถูกฉีดเข้าไปในทุกเซสชัน) เก็บบันทึกระยะยาวไว้ใน `MEMORY.md` และเข้าถึงเมื่อต้องการด้วยเครื่องมือหน่วยความจำ + หากคุณต้องการบริบทร่วมในทุกช่อง ให้ใส่คำสั่งที่คงที่ไว้ใน `AGENTS.md` หรือ `USER.md` (ไฟล์เหล่านี้ถูกฉีดเข้าไปในทุกเซสชัน) เก็บบันทึกระยะยาวไว้ใน `MEMORY.md` และเข้าถึงตามต้องการด้วยเครื่องมือ memory -ตอนนี้สร้างช่องบางช่องบนเซิร์ฟเวอร์ Discord ของคุณแล้วเริ่มแชตได้เลย เอเจนต์ของคุณสามารถเห็นชื่อช่อง และแต่ละช่องจะมีเซสชันแยกของตัวเอง ดังนั้นคุณจึงตั้งค่า `#coding`, `#home`, `#research` หรืออะไรก็ได้ที่เหมาะกับเวิร์กโฟลว์ของคุณ +ตอนนี้ให้สร้างช่องบางส่วนบนเซิร์ฟเวอร์ Discord ของคุณและเริ่มแชต เอเจนต์ของคุณมองเห็นชื่อช่องได้ และแต่ละช่องจะได้รับเซสชันแยกของตัวเอง — ดังนั้นคุณสามารถตั้งค่า `#coding`, `#home`, `#research` หรืออะไรก็ตามที่เหมาะกับเวิร์กโฟลว์ของคุณ ## โมเดลรันไทม์ - Gateway เป็นเจ้าของการเชื่อมต่อ Discord. -- การกำหนดเส้นทางการตอบกลับเป็นแบบกำหนดตายตัว: ข้อความตอบกลับขาเข้าจาก Discord จะย้อนกลับไปยัง Discord. -- เมทาดาทาของ guild/channel ใน Discord จะถูกเพิ่มลงในพรอมป์ของโมเดลในฐานะบริบทที่ไม่น่าเชื่อถือ ไม่ใช่คำนำหน้าการตอบกลับที่ผู้ใช้เห็น หากโมเดลคัดลอกซองข้อมูลนั้นกลับมา OpenClaw จะลบเมทาดาทาที่ถูกคัดลอกออกจากคำตอบขาออกและจากบริบทการเล่นซ้ำในอนาคต. +- การกำหนดเส้นทางคำตอบเป็นแบบกำหนดแน่นอน: คำตอบขาเข้าจาก Discord จะตอบกลับไปยัง Discord. +- เมตาดาต้า guild/channel ของ Discord จะถูกเพิ่มเข้าไปในพรอมป์ของโมเดลเป็นบริบทที่ไม่น่าเชื่อถือ + ไม่ใช่เป็นคำนำหน้าคำตอบที่ผู้ใช้มองเห็น หากโมเดลคัดลอกซองข้อมูลนั้น + กลับมา OpenClaw จะตัดเมตาดาต้าที่ถูกคัดลอกออกจากคำตอบขาออกและจาก + บริบท replay ในอนาคต. - โดยค่าเริ่มต้น (`session.dmScope=main`) แชตโดยตรงจะแชร์เซสชันหลักของเอเจนต์ (`agent:main:main`). -- ช่อง guild จะถูกแยกเป็นคีย์เซสชัน (`agent::discord:channel:`). -- Group DM จะถูกละเว้นโดยค่าเริ่มต้น (`channels.discord.dm.groupEnabled=false`). -- คำสั่ง slash แบบเนทีฟจะทำงานในเซสชันคำสั่งที่แยกไว้ (`agent::discord:slash:`) โดยยังคงพา `CommandTargetSessionKey` ไปยังเซสชันการสนทนาที่ถูกกำหนดเส้นทาง. -- การส่งประกาศ cron/heartbeat แบบข้อความล้วนไปยัง Discord จะใช้คำตอบสุดท้ายที่ assistant มองเห็นเพียงครั้งเดียว เพย์โหลดสื่อและคอมโพเนนต์แบบมีโครงสร้างยังคงเป็นหลายข้อความเมื่อเอเจนต์ปล่อยเพย์โหลดที่ส่งได้หลายรายการ. +- ช่อง guild เป็นคีย์เซสชันที่แยกกัน (`agent::discord:channel:`). +- Group DM จะถูกเพิกเฉยโดยค่าเริ่มต้น (`channels.discord.dm.groupEnabled=false`). +- คำสั่ง slash แบบเนทีฟจะทำงานในเซสชันคำสั่งที่แยกกัน (`agent::discord:slash:`) โดยยังคงพก `CommandTargetSessionKey` ไปยังเซสชันการสนทนาที่ถูกกำหนดเส้นทาง. +- การส่งประกาศ cron/heartbeat แบบข้อความเท่านั้นไปยัง Discord ใช้คำตอบสุดท้าย + ที่ผู้ช่วยมองเห็นเพียงครั้งเดียว ส่วนเพย์โหลดสื่อและคอมโพเนนต์แบบมีโครงสร้างยังคงเป็น + หลายข้อความเมื่อเอเจนต์ปล่อยเพย์โหลดที่ส่งได้หลายรายการ. -## ช่องฟอรัม +## ช่อง Forum -ช่องฟอรัมและช่องสื่อของ Discord รับเฉพาะโพสต์ในเธรดเท่านั้น OpenClaw รองรับสองวิธีในการสร้างโพสต์เหล่านี้: +ช่อง forum และ media ของ Discord รับได้เฉพาะโพสต์ thread เท่านั้น OpenClaw รองรับสองวิธีในการสร้าง: -- ส่งข้อความไปยังฟอรัมหลัก (`channel:`) เพื่อสร้างเธรดอัตโนมัติ ชื่อเธรดจะใช้บรรทัดแรกที่ไม่ว่างของข้อความของคุณ. -- ใช้ `openclaw message thread create` เพื่อสร้างเธรดโดยตรง อย่าส่ง `--message-id` สำหรับช่องฟอรัม. +- ส่งข้อความไปยัง parent ของ forum (`channel:`) เพื่อสร้าง thread อัตโนมัติ ชื่อ thread ใช้บรรทัดแรกที่ไม่ว่างของข้อความคุณ. +- ใช้ `openclaw message thread create` เพื่อสร้าง thread โดยตรง อย่าส่ง `--message-id` สำหรับช่อง forum. -ตัวอย่าง: ส่งไปยังฟอรัมหลักเพื่อสร้างเธรด +ตัวอย่าง: ส่งไปยัง parent ของ forum เพื่อสร้าง thread ```bash openclaw message send --channel discord --target channel: \ --message "Topic title\nBody of the post" ``` -ตัวอย่าง: สร้างเธรดฟอรัมอย่างชัดเจน +ตัวอย่าง: สร้าง forum thread อย่างชัดเจน ```bash openclaw message thread create --channel discord --target channel: \ --thread-name "Topic title" --message "Body of the post" ``` -ฟอรัมหลักไม่รับคอมโพเนนต์ของ Discord หากคุณต้องการคอมโพเนนต์ ให้ส่งไปยังเธรดนั้นเอง (`channel:`). +parent ของ forum ไม่รับคอมโพเนนต์ Discord หากคุณต้องการคอมโพเนนต์ ให้ส่งไปยัง thread เอง (`channel:`). ## คอมโพเนนต์แบบโต้ตอบ -OpenClaw รองรับคอนเทนเนอร์คอมโพเนนต์ v2 ของ Discord สำหรับข้อความของเอเจนต์ ใช้เครื่องมือข้อความพร้อมเพย์โหลด `components` ผลลัพธ์การโต้ตอบจะถูกกำหนดเส้นทางกลับไปยังเอเจนต์เป็นข้อความขาเข้าปกติ และทำตามการตั้งค่า Discord `replyToMode` ที่มีอยู่. +OpenClaw รองรับคอนเทนเนอร์ Discord components v2 สำหรับข้อความของเอเจนต์ ใช้เครื่องมือ message พร้อมเพย์โหลด `components` ผลลัพธ์การโต้ตอบจะถูกกำหนดเส้นทางกลับไปยังเอเจนต์เป็นข้อความขาเข้าปกติ และปฏิบัติตามการตั้งค่า Discord `replyToMode` ที่มีอยู่. บล็อกที่รองรับ: - `text`, `section`, `separator`, `actions`, `media-gallery`, `file` -- แถวการดำเนินการอนุญาตปุ่มได้สูงสุด 5 ปุ่มหรือเมนูเลือกเดียวหนึ่งเมนู -- ประเภทการเลือก: `string`, `user`, `role`, `mentionable`, `channel` +- แถว action อนุญาตให้มีปุ่มได้สูงสุด 5 ปุ่ม หรือเมนู select เดี่ยวหนึ่งเมนู +- ประเภท select: `string`, `user`, `role`, `mentionable`, `channel` -โดยค่าเริ่มต้น คอมโพเนนต์ใช้ได้ครั้งเดียว ตั้งค่า `components.reusable=true` เพื่ออนุญาตให้ใช้ปุ่ม เมนูเลือก และฟอร์มได้หลายครั้งจนกว่าจะหมดอายุ. +โดยค่าเริ่มต้น คอมโพเนนต์ใช้ได้ครั้งเดียว ตั้งค่า `components.reusable=true` เพื่อให้ปุ่ม, select และฟอร์มใช้งานได้หลายครั้งจนกว่าจะหมดอายุ. -หากต้องการจำกัดว่าใครคลิกปุ่มได้ ให้ตั้งค่า `allowedUsers` บนปุ่มนั้น (ID ผู้ใช้ Discord, แท็ก หรือ `*`) เมื่อกำหนดค่าแล้ว ผู้ใช้ที่ไม่ตรงกันจะได้รับการปฏิเสธแบบ ephemeral. +เพื่อจำกัดว่าใครสามารถคลิกปุ่มได้ ให้ตั้งค่า `allowedUsers` บนปุ่มนั้น (Discord user IDs, tags หรือ `*`) เมื่อกำหนดค่าแล้ว ผู้ใช้ที่ไม่ตรงกันจะได้รับการปฏิเสธแบบ ephemeral. -คำสั่ง slash `/model` และ `/models` จะเปิดตัวเลือกโมเดลแบบโต้ตอบพร้อม dropdown สำหรับ provider, โมเดล และ runtime ที่เข้ากันได้ รวมถึงขั้นตอน Submit `/models add` เลิกใช้แล้วและตอนนี้จะส่งคืนข้อความแจ้งการเลิกใช้แทนการลงทะเบียนโมเดลจากแชต การตอบกลับของตัวเลือกเป็นแบบ ephemeral และมีเพียงผู้ใช้ที่เรียกใช้เท่านั้นที่ใช้ได้. +คำสั่ง slash `/model` และ `/models` จะเปิดตัวเลือกโมเดลแบบโต้ตอบที่มี dropdown ของ provider, model และ runtime ที่เข้ากันได้ พร้อมขั้นตอน Submit `/models add` เลิกใช้แล้วและตอนนี้ส่งคืนข้อความเลิกใช้แทนการลงทะเบียนโมเดลจากแชต คำตอบของตัวเลือกเป็นแบบ ephemeral และมีเพียงผู้ใช้ที่เรียกใช้เท่านั้นที่ใช้งานได้. ไฟล์แนบ: -- บล็อก `file` ต้องชี้ไปยังการอ้างอิงไฟล์แนบ (`attachment://`) +- บล็อก `file` ต้องชี้ไปยังการอ้างอิง attachment (`attachment://`) - ระบุไฟล์แนบผ่าน `media`/`path`/`filePath` (ไฟล์เดียว); ใช้ `media-gallery` สำหรับหลายไฟล์ -- ใช้ `filename` เพื่อแทนที่ชื่ออัปโหลดเมื่อควรตรงกับการอ้างอิงไฟล์แนบ +- ใช้ `filename` เพื่อแทนที่ชื่ออัปโหลดเมื่อควรตรงกับการอ้างอิง attachment ฟอร์ม modal: -- เพิ่ม `components.modal` พร้อมฟิลด์ได้สูงสุด 5 ฟิลด์ +- เพิ่ม `components.modal` โดยมีฟิลด์ได้สูงสุด 5 ฟิลด์ - ประเภทฟิลด์: `text`, `checkbox`, `radio`, `select`, `role-select`, `user-select` -- OpenClaw เพิ่มปุ่มทริกเกอร์โดยอัตโนมัติ +- OpenClaw เพิ่มปุ่ม trigger ให้อัตโนมัติ ตัวอย่าง: @@ -425,38 +430,38 @@ OpenClaw รองรับคอนเทนเนอร์คอมโพเ ## การควบคุมการเข้าถึงและการกำหนดเส้นทาง - - `channels.discord.dmPolicy` ควบคุมการเข้าถึง DM `channels.discord.allowFrom` คือ allowlist สำหรับ DM ตามมาตรฐาน. + + `channels.discord.dmPolicy` ควบคุมการเข้าถึง DM `channels.discord.allowFrom` คือ allowlist ของ DM ที่เป็นมาตรฐาน. - `pairing` (ค่าเริ่มต้น) - `allowlist` - `open` (ต้องให้ `channels.discord.allowFrom` รวม `"*"`) - `disabled` - หากนโยบาย DM ไม่ใช่แบบเปิด ผู้ใช้ที่ไม่รู้จักจะถูกบล็อก (หรือได้รับพรอมป์ให้จับคู่ในโหมด `pairing`). + หากนโยบาย DM ไม่ใช่ open ผู้ใช้ที่ไม่รู้จักจะถูกบล็อก (หรือได้รับพรอมป์ให้ pairing ในโหมด `pairing`). - ลำดับความสำคัญสำหรับหลายบัญชี: + ลำดับความสำคัญแบบหลายบัญชี: - `channels.discord.accounts.default.allowFrom` ใช้กับบัญชี `default` เท่านั้น. - - สำหรับบัญชีเดียว `allowFrom` มีลำดับความสำคัญเหนือ `dm.allowFrom` แบบเดิม. - - บัญชีที่มีชื่อจะสืบทอด `channels.discord.allowFrom` เมื่อ `allowFrom` ของตัวเองและ `dm.allowFrom` แบบเดิมไม่ได้ตั้งค่า. + - สำหรับบัญชีเดียว `allowFrom` มีความสำคัญเหนือกว่า `dm.allowFrom` แบบ legacy. + - บัญชีที่มีชื่อจะสืบทอด `channels.discord.allowFrom` เมื่อ `allowFrom` ของตัวเองและ `dm.allowFrom` แบบ legacy ไม่ได้ตั้งค่าไว้. - บัญชีที่มีชื่อจะไม่สืบทอด `channels.discord.accounts.default.allowFrom`. - `channels.discord.dm.policy` และ `channels.discord.dm.allowFrom` แบบเดิมยังถูกอ่านเพื่อความเข้ากันได้ `openclaw doctor --fix` จะย้ายค่าเหล่านั้นไปยัง `dmPolicy` และ `allowFrom` เมื่อทำได้โดยไม่เปลี่ยนการเข้าถึง. + `channels.discord.dm.policy` และ `channels.discord.dm.allowFrom` แบบ legacy ยังอ่านเพื่อความเข้ากันได้ `openclaw doctor --fix` จะย้ายไปยัง `dmPolicy` และ `allowFrom` เมื่อสามารถทำได้โดยไม่เปลี่ยนการเข้าถึง. รูปแบบเป้าหมาย DM สำหรับการส่ง: - `user:` - - การ mention แบบ `<@id>` + - การ mention `<@id>` - โดยปกติ ID ตัวเลขล้วนจะ resolve เป็น ID ช่องเมื่อมีค่าเริ่มต้นของช่องที่ใช้งานอยู่ แต่ ID ที่อยู่ใน DM `allowFrom` ที่มีผลของบัญชีจะถูกถือเป็นเป้าหมาย DM ของผู้ใช้เพื่อความเข้ากันได้. + ID ตัวเลขล้วนโดยปกติจะ resolve เป็น channel IDs เมื่อมีค่าเริ่มต้นของช่องที่ใช้งานอยู่ แต่ ID ที่อยู่ใน `allowFrom` ของ DM ที่มีผลของบัญชีจะถูกถือเป็นเป้าหมาย user DM เพื่อความเข้ากันได้. - - DM ของ Discord สามารถใช้รายการ `accessGroup:` แบบไดนามิกใน `channels.discord.allowFrom`. + + Discord DMs สามารถใช้รายการ `accessGroup:` แบบไดนามิกใน `channels.discord.allowFrom`. - ชื่อ access group ใช้ร่วมกันระหว่างช่องข้อความ ใช้ `type: "message.senders"` สำหรับกลุ่มแบบคงที่ซึ่งสมาชิกแสดงด้วยไวยากรณ์ `allowFrom` ปกติของแต่ละช่อง หรือใช้ `type: "discord.channelAudience"` เมื่อผู้ชม `ViewChannel` ปัจจุบันของช่อง Discord ควรกำหนดสมาชิกแบบไดนามิก พฤติกรรม access-group ที่ใช้ร่วมกันมีเอกสารไว้ที่นี่: [กลุ่มการเข้าถึง](/th/channels/access-groups). + ชื่อกลุ่มการเข้าถึงใช้ร่วมกันระหว่างช่องข้อความ ใช้ `type: "message.senders"` สำหรับกลุ่ม static ที่สมาชิกแสดงด้วยไวยากรณ์ `allowFrom` ปกติของแต่ละช่อง หรือ `type: "discord.channelAudience"` เมื่อผู้ชม `ViewChannel` ปัจจุบันของช่อง Discord ควรกำหนดสมาชิกแบบไดนามิก พฤติกรรมกลุ่มการเข้าถึงที่ใช้ร่วมกันมีเอกสารไว้ที่นี่: [กลุ่มการเข้าถึง](/th/channels/access-groups). ```json5 { @@ -479,9 +484,9 @@ OpenClaw รองรับคอนเทนเนอร์คอมโพเ } ``` - ช่องข้อความของ Discord ไม่มีรายชื่อสมาชิกแยกต่างหาก `type: "discord.channelAudience"` จำลองสมาชิกภาพดังนี้: ผู้ส่ง DM เป็นสมาชิกของ guild ที่กำหนดค่าและปัจจุบันมีสิทธิ์ `ViewChannel` ที่มีผลบนช่องที่กำหนดค่าหลังจากนำ role และการ override ของช่องมาใช้แล้ว. + ช่องข้อความ Discord ไม่มีรายการสมาชิกแยกต่างหาก `type: "discord.channelAudience"` จำลองสมาชิกว่า: ผู้ส่ง DM เป็นสมาชิกของ guild ที่กำหนดค่าไว้ และปัจจุบันมีสิทธิ์ `ViewChannel` ที่มีผลบนช่องที่กำหนดค่าไว้หลังจากนำ role และ channel overwrites ไปใช้แล้ว. - ตัวอย่าง: อนุญาตให้ทุกคนที่เห็น `#maintainers` ได้ DM ไปยังบอท ขณะที่ยังปิด DM สำหรับคนอื่นทั้งหมด. + ตัวอย่าง: อนุญาตให้ทุกคนที่เห็น `#maintainers` สามารถ DM ไปยังบอตได้ ขณะยังปิด DM สำหรับคนอื่นทั้งหมด. ```json5 { @@ -502,7 +507,7 @@ OpenClaw รองรับคอนเทนเนอร์คอมโพเ } ``` - คุณสามารถผสมรายการแบบไดนามิกและแบบคงที่ได้: + คุณสามารถผสมรายการ dynamic และ static ได้: ```json5 { @@ -522,13 +527,13 @@ OpenClaw รองรับคอนเทนเนอร์คอมโพเ } ``` - การค้นหาจะล้มเหลวแบบปิด หาก Discord ส่งคืน `Missing Access`, การค้นหาสมาชิกล้มเหลว หรือช่องอยู่ใน guild อื่น ผู้ส่ง DM จะถูกถือว่าไม่ได้รับอนุญาต. + การ lookup จะล้มเหลวแบบปิด หาก Discord ส่งคืน `Missing Access`, การ lookup สมาชิกไม่สำเร็จ หรือช่องเป็นของ guild อื่น ผู้ส่ง DM จะถูกถือว่าไม่ได้รับอนุญาต. - เปิดใช้ **Server Members Intent** ใน Discord Developer Portal สำหรับบอทเมื่อใช้ access group แบบ channel-audience DM ไม่มีสถานะสมาชิก guild ดังนั้น OpenClaw จะ resolve สมาชิกผ่าน Discord REST ณ เวลาตรวจสอบสิทธิ์. + เปิดใช้ **Server Members Intent** ใน Discord Developer Portal สำหรับบอตเมื่อใช้กลุ่มการเข้าถึงแบบ channel-audience DM ไม่มีสถานะสมาชิก guild ดังนั้น OpenClaw จะ resolve สมาชิกผ่าน Discord REST ณ เวลาตรวจสอบสิทธิ์. - + การจัดการ guild ถูกควบคุมโดย `channels.discord.groupPolicy`: - `open` @@ -539,12 +544,12 @@ OpenClaw รองรับคอนเทนเนอร์คอมโพเ พฤติกรรม `allowlist`: - - guild ต้องตรงกับ `channels.discord.guilds` (แนะนำให้ใช้ `id`, ยอมรับ slug) - - allowlist ของผู้ส่งแบบไม่บังคับ: `users` (แนะนำ ID ที่เสถียร) และ `roles` (เฉพาะ ID ของ role); หากกำหนดอย่างใดอย่างหนึ่ง ผู้ส่งจะได้รับอนุญาตเมื่อ ตรงกับ `users` หรือ `roles` - - การจับคู่ชื่อ/แท็กโดยตรงถูกปิดโดยค่าเริ่มต้น; เปิดใช้ `channels.discord.dangerouslyAllowNameMatching: true` เฉพาะเป็นโหมดความเข้ากันได้แบบฉุกเฉิน - - รองรับชื่อ/แท็กสำหรับ `users` แต่ ID ปลอดภัยกว่า; `openclaw security audit` จะเตือนเมื่อมีการใช้รายการชื่อ/แท็ก - - หาก guild มีการกำหนดค่า `channels` ช่องที่ไม่ได้อยู่ในรายการจะถูกปฏิเสธ - - หาก guild ไม่มีบล็อก `channels` ช่องทั้งหมดใน guild ที่อยู่ใน allowlist นั้นจะได้รับอนุญาต + - guild ต้องตรงกับ `channels.discord.guilds` (`id` แนะนำ, slug ยอมรับได้) + - allowlist ผู้ส่งแบบเลือกได้: `users` (แนะนำ stable IDs) และ `roles` (role IDs เท่านั้น); หากกำหนดค่าอย่างใดอย่างหนึ่ง ผู้ส่งจะได้รับอนุญาตเมื่อจับคู่กับ `users` หรือ `roles` + - การจับคู่ชื่อ/tag โดยตรงถูกปิดใช้งานโดยค่าเริ่มต้น; เปิดใช้ `channels.discord.dangerouslyAllowNameMatching: true` เฉพาะเป็นโหมดความเข้ากันได้แบบ break-glass + - รองรับชื่อ/tags สำหรับ `users` แต่ ID ปลอดภัยกว่า; `openclaw security audit` จะเตือนเมื่อใช้รายการชื่อ/tag + - หาก guild มีการกำหนดค่า `channels` ช่องที่ไม่อยู่ในรายการจะถูกปฏิเสธ + - หาก guild ไม่มีบล็อก `channels` ทุกช่องใน guild ที่อยู่ใน allowlist นั้นจะได้รับอนุญาต ตัวอย่าง: @@ -570,35 +575,35 @@ OpenClaw รองรับคอนเทนเนอร์คอมโพเ } ``` - หากคุณตั้งค่าเพียง `DISCORD_BOT_TOKEN` และไม่ได้สร้างบล็อก `channels.discord` fallback ขณะรันจะเป็น `groupPolicy="allowlist"` (พร้อมคำเตือนใน log) แม้ว่า `channels.defaults.groupPolicy` จะเป็น `open`. + หากคุณตั้งค่าเฉพาะ `DISCORD_BOT_TOKEN` และไม่ได้สร้างบล็อก `channels.discord` runtime fallback คือ `groupPolicy="allowlist"` (พร้อมคำเตือนใน logs) แม้ว่า `channels.defaults.groupPolicy` จะเป็น `open`. - - ข้อความ guild ต้องผ่าน mention gate โดยค่าเริ่มต้น. + + ข้อความ guild ถูก gate ด้วย mention โดยค่าเริ่มต้น. การตรวจจับ mention รวมถึง: - - การ mention บอทอย่างชัดเจน - - รูปแบบ mention ที่กำหนดค่า (`agents.list[].groupChat.mentionPatterns`, fallback `messages.groupChat.mentionPatterns`) - - พฤติกรรมตอบกลับถึงบอทโดยนัยในกรณีที่รองรับ + - การ mention บอตอย่างชัดเจน + - รูปแบบ mention ที่กำหนดค่าไว้ (`agents.list[].groupChat.mentionPatterns`, fallback `messages.groupChat.mentionPatterns`) + - พฤติกรรม reply-to-bot โดยนัยในกรณีที่รองรับ - เมื่อเขียนข้อความ Discord ขาออก ให้ใช้ไวยากรณ์ mention ตามมาตรฐาน: `<@USER_ID>` สำหรับผู้ใช้, `<#CHANNEL_ID>` สำหรับช่อง และ `<@&ROLE_ID>` สำหรับ role อย่าใช้รูปแบบ mention ชื่อเล่นแบบเดิม `<@!USER_ID>`. + เมื่อเขียนข้อความ Discord ขาออก ให้ใช้ไวยากรณ์ mention มาตรฐาน: `<@USER_ID>` สำหรับผู้ใช้, `<#CHANNEL_ID>` สำหรับช่อง และ `<@&ROLE_ID>` สำหรับ roles อย่าใช้รูปแบบ mention ชื่อเล่น legacy `<@!USER_ID>`. `requireMention` ถูกกำหนดค่าต่อ guild/channel (`channels.discord.guilds...`). - `ignoreOtherMentions` สามารถเลือกให้ทิ้งข้อความที่ mention ผู้ใช้/role อื่นแต่ไม่ได้ mention บอท (ยกเว้น @everyone/@here). + `ignoreOtherMentions` เลือกได้ว่าจะทิ้งข้อความที่ mention ผู้ใช้/role อื่นแต่ไม่ใช่บอต (ยกเว้น @everyone/@here). - Group DM: + Group DMs: - - ค่าเริ่มต้น: ถูกละเว้น (`dm.groupEnabled=false`) - - allowlist แบบไม่บังคับผ่าน `dm.groupChannels` (ID ช่องหรือ slug) + - ค่าเริ่มต้น: ถูกเพิกเฉย (`dm.groupEnabled=false`) + - allowlist แบบเลือกได้ผ่าน `dm.groupChannels` (channel IDs หรือ slugs) ### การกำหนดเส้นทางเอเจนต์ตาม role -ใช้ `bindings[].match.roles` เพื่อกำหนดเส้นทางสมาชิก guild ของ Discord ไปยังเอเจนต์ต่างกันตาม ID ของ role การ binding ตาม role รับเฉพาะ ID ของ role และจะถูกประเมินหลังจาก binding แบบ peer หรือ parent-peer และก่อน binding แบบ guild-only หาก binding ตั้งค่าฟิลด์ match อื่นด้วย (เช่น `peer` + `guildId` + `roles`) ฟิลด์ที่กำหนดค่าทั้งหมดต้องตรงกัน. +ใช้ `bindings[].match.roles` เพื่อกำหนดเส้นทางสมาชิก guild ของ Discord ไปยังเอเจนต์ต่างกันตาม role ID bindings ตาม role รับเฉพาะ role IDs และจะถูกประเมินหลังจาก bindings แบบ peer หรือ parent-peer และก่อน bindings แบบ guild-only หาก binding ตั้งค่าฟิลด์ match อื่นด้วย (เช่น `peer` + `guildId` + `roles`) ฟิลด์ที่กำหนดค่าทั้งหมดต้องตรงกัน. ```json5 { @@ -622,15 +627,15 @@ OpenClaw รองรับคอนเทนเนอร์คอมโพเ } ``` -## คำสั่งเนทีฟและการยืนยันสิทธิ์คำสั่ง +## คำสั่งเนทีฟและการตรวจสอบสิทธิ์คำสั่ง -- `commands.native` มีค่าเริ่มต้นเป็น `"auto"` และเปิดใช้สำหรับ Discord -- การเขียนทับรายช่องทาง: `channels.discord.commands.native` -- `commands.native=false` จะข้ามการลงทะเบียนและการล้างคำสั่ง slash ของ Discord ระหว่างเริ่มต้น คำสั่งที่เคยลงทะเบียนไว้ก่อนหน้านี้อาจยังมองเห็นได้ใน Discord จนกว่าคุณจะนำออกจากแอป Discord -- การยืนยันตัวตนของคำสั่งแบบเนทีฟใช้ allowlist/นโยบาย Discord ชุดเดียวกับการจัดการข้อความปกติ -- คำสั่งอาจยังมองเห็นได้ใน UI ของ Discord สำหรับผู้ใช้ที่ไม่ได้รับอนุญาต แต่การเรียกใช้ยังคงบังคับใช้การยืนยันตัวตนของ OpenClaw และส่งคืน "ไม่ได้รับอนุญาต" +- `commands.native` มีค่าเริ่มต้นเป็น `"auto"` และเปิดใช้สำหรับ Discord. +- การแทนที่รายช่องทาง: `channels.discord.commands.native`. +- `commands.native=false` จะข้ามการลงทะเบียนและการล้างคำสั่ง slash ของ Discord ระหว่างการเริ่มต้น คำสั่งที่ลงทะเบียนไว้ก่อนหน้านี้อาจยังแสดงใน Discord จนกว่าคุณจะลบออกจากแอป Discord. +- การยืนยันสิทธิ์คำสั่งแบบเนทีฟใช้ allowlist/นโยบาย Discord เดียวกับการจัดการข้อความปกติ. +- คำสั่งอาจยังแสดงใน UI ของ Discord สำหรับผู้ใช้ที่ไม่ได้รับอนุญาต แต่การเรียกใช้ยังบังคับใช้การยืนยันสิทธิ์ของ OpenClaw และส่งคืน "not authorized". -ดู [คำสั่ง Slash](/th/tools/slash-commands) สำหรับแค็ตตาล็อกคำสั่งและพฤติกรรม +ดู [คำสั่ง Slash](/th/tools/slash-commands) สำหรับแค็ตตาล็อกคำสั่งและพฤติกรรม. การตั้งค่าคำสั่ง slash เริ่มต้น: @@ -640,7 +645,7 @@ OpenClaw รองรับคอนเทนเนอร์คอมโพเ - Discord รองรับแท็กตอบกลับในเอาต์พุตของเอเจนต์: + Discord รองรับแท็กตอบกลับในผลลัพธ์ของเอเจนต์: - `[[reply_to_current]]` - `[[reply_to:]]` @@ -652,21 +657,21 @@ OpenClaw รองรับคอนเทนเนอร์คอมโพเ - `all` - `batched` - หมายเหตุ: `off` ปิดการจัดเธรดการตอบกลับโดยนัย แท็ก `[[reply_to_*]]` ที่ระบุชัดเจนยังคงใช้งานได้ - `first` จะแนบการอ้างอิงการตอบกลับแบบเนทีฟโดยนัยกับข้อความ Discord ขาออกแรกของรอบนั้นเสมอ + หมายเหตุ: `off` ปิดการทำเธรดตอบกลับโดยนัย แท็ก `[[reply_to_*]]` แบบระบุชัดเจนยังคงทำงาน. + `first` จะแนบการอ้างอิงการตอบกลับแบบเนทีฟโดยนัยเข้ากับข้อความ Discord ขาออกแรกของรอบเสมอ. `batched` จะแนบการอ้างอิงการตอบกลับแบบเนทีฟโดยนัยของ Discord เฉพาะเมื่อ - รอบขาเข้าเป็นชุดข้อความหลายข้อความที่ถูกรวมด้วย debounce เท่านั้น วิธีนี้มีประโยชน์ - เมื่อคุณต้องการการตอบกลับแบบเนทีฟเป็นหลักสำหรับแชตที่ส่งถี่และคลุมเครือ ไม่ใช่ทุก - รอบที่มีข้อความเดียว + รอบขาเข้าเป็นชุดข้อความหลายข้อความที่ผ่านการหน่วงรวมแล้ว สิ่งนี้มีประโยชน์ + เมื่อคุณต้องการการตอบกลับแบบเนทีฟสำหรับแชตที่มาเป็นชุดและกำกวมเป็นหลัก ไม่ใช่ทุก + รอบที่มีข้อความเดียว. - ID ข้อความจะแสดงในบริบท/ประวัติ เพื่อให้เอเจนต์สามารถเจาะจงข้อความเป้าหมายได้ + ID ข้อความจะแสดงในบริบท/ประวัติเพื่อให้เอเจนต์สามารถเล็งไปยังข้อความเฉพาะได้. - OpenClaw สามารถสตรีมร่างคำตอบได้โดยส่งข้อความชั่วคราวและแก้ไขเมื่อมีข้อความเข้ามา `channels.discord.streaming` รับค่า `off` (ค่าเริ่มต้น) | `partial` | `block` | `progress` `progress` จะคงร่างสถานะที่แก้ไขได้หนึ่งรายการไว้ และอัปเดตด้วยความคืบหน้าของเครื่องมือจนกว่าจะส่งคำตอบสุดท้าย; `streamMode` เป็น alias เดิมและจะถูกย้ายให้อัตโนมัติ + OpenClaw สามารถสตรีมร่างคำตอบได้โดยส่งข้อความชั่วคราวและแก้ไขเมื่อมีข้อความเข้ามา `channels.discord.streaming` รับค่า `off` (ค่าเริ่มต้น) | `partial` | `block` | `progress`. `progress` จะคงร่างสถานะที่แก้ไขได้หนึ่งรายการและอัปเดตด้วยความคืบหน้าของเครื่องมือจนกว่าจะส่งผลลัพธ์สุดท้าย; `streamMode` เป็น alias แบบเก่าและจะถูกย้ายให้อัตโนมัติ. - ค่าเริ่มต้นยังคงเป็น `off` เพราะการแก้ไขตัวอย่างของ Discord จะชน rate limit ได้เร็วเมื่อมีบอตหรือ Gateway หลายตัวใช้บัญชีเดียวกัน + ค่าเริ่มต้นยังคงเป็น `off` เพราะการแก้ไขตัวอย่างของ Discord จะชนขีดจำกัดอัตราอย่างรวดเร็วเมื่อบอตหรือ Gateway หลายตัวใช้บัญชีเดียวกัน. ```json5 { @@ -683,12 +688,31 @@ OpenClaw รองรับคอนเทนเนอร์คอมโพเ } ``` - - `partial` แก้ไขข้อความตัวอย่างเดียวเมื่อ token เข้ามา - - `block` ส่งชิ้นส่วนขนาดร่างออกมา (ใช้ `draftChunk` เพื่อปรับขนาดและจุดแบ่ง โดยจำกัดไว้ที่ `textChunkLimit`) - - ผลลัพธ์สุดท้ายที่เป็นสื่อ ข้อผิดพลาด และการตอบกลับที่ระบุชัดเจนจะยกเลิกการแก้ไขตัวอย่างที่ค้างอยู่ - - `streaming.preview.toolProgress` (ค่าเริ่มต้น `true`) ควบคุมว่าจะนำข้อความตัวอย่างกลับมาใช้กับการอัปเดตเครื่องมือ/ความคืบหน้าหรือไม่ + - `partial` แก้ไขข้อความตัวอย่างเดียวเมื่อโทเค็นเข้ามา. + - `block` ส่งชิ้นส่วนขนาดร่างออกมา (ใช้ `draftChunk` เพื่อปรับขนาดและจุดตัด โดยถูกจำกัดไม่เกิน `textChunkLimit`). + - สื่อ ข้อผิดพลาด และผลลัพธ์สุดท้ายที่ตอบกลับแบบระบุชัดเจนจะยกเลิกการแก้ไขตัวอย่างที่ค้างอยู่. + - `streaming.preview.toolProgress` (ค่าเริ่มต้น `true`) ควบคุมว่าการอัปเดตเครื่องมือ/ความคืบหน้าจะใช้ข้อความตัวอย่างซ้ำหรือไม่. + - `streaming.preview.commandText` / `streaming.progress.commandText` ควบคุมรายละเอียดคำสั่ง/การรันในบรรทัดความคืบหน้าแบบกะทัดรัด: `raw` (ค่าเริ่มต้น) หรือ `status` (เฉพาะป้ายกำกับเครื่องมือ). - การสตรีมตัวอย่างรองรับเฉพาะข้อความเท่านั้น; การตอบกลับด้วยสื่อจะย้อนกลับไปใช้การส่งตามปกติ เมื่อเปิดใช้การสตรีม `block` อย่างชัดเจน OpenClaw จะข้ามสตรีมตัวอย่างเพื่อหลีกเลี่ยงการสตรีมซ้ำซ้อน + ซ่อนข้อความคำสั่ง/การรันดิบโดยยังคงบรรทัดความคืบหน้าแบบกะทัดรัดไว้: + + ```json + { + "channels": { + "discord": { + "streaming": { + "mode": "progress", + "progress": { + "toolProgress": true, + "commandText": "status" + } + } + } + } + } + ``` + + การสตรีมตัวอย่างรองรับเฉพาะข้อความ; การตอบกลับด้วยสื่อจะย้อนกลับไปใช้การส่งแบบปกติ เมื่อเปิดใช้การสตรีม `block` อย่างชัดเจน OpenClaw จะข้ามสตรีมตัวอย่างเพื่อหลีกเลี่ยงการสตรีมซ้ำ. @@ -696,8 +720,8 @@ OpenClaw รองรับคอนเทนเนอร์คอมโพเ บริบทประวัติของกิลด์: - `channels.discord.historyLimit` ค่าเริ่มต้น `20` - - ทางเลือกสำรอง: `messages.groupChat.historyLimit` - - `0` ปิดใช้ + - ค่าทดแทน: `messages.groupChat.historyLimit` + - `0` ปิดใช้งาน การควบคุมประวัติ DM: @@ -706,28 +730,28 @@ OpenClaw รองรับคอนเทนเนอร์คอมโพเ พฤติกรรมเธรด: - - เธรด Discord จะถูกกำหนดเส้นทางเป็นเซสชันช่องทางและสืบทอดค่าคอนฟิกช่องทางแม่ เว้นแต่จะมีการเขียนทับ - - เซสชันเธรดสืบทอดการเลือก `/model` ระดับเซสชันของช่องทางแม่เป็นทางเลือกสำรองเฉพาะโมเดล; การเลือก `/model` ภายในเธรดยังคงมีลำดับความสำคัญสูงกว่า และจะไม่คัดลอกประวัติ transcript ของแม่ เว้นแต่จะเปิดใช้การสืบทอด transcript - - `channels.discord.thread.inheritParent` (ค่าเริ่มต้น `false`) เลือกให้ auto-thread ใหม่เริ่มด้วยข้อมูลจาก transcript ของแม่ การเขียนทับรายบัญชีอยู่ใต้ `channels.discord.accounts..thread.inheritParent` - - reaction ของ message-tool สามารถ resolve เป้าหมาย DM แบบ `user:` ได้ - - `guilds..channels..requireMention: false` จะถูกคงไว้ระหว่างทางเลือกสำรองของการเปิดใช้งานขั้นตอบกลับ + - เธรด Discord จะถูกกำหนดเส้นทางเป็นเซสชันช่องทางและสืบทอดการกำหนดค่าช่องทางแม่ เว้นแต่มีการแทนที่. + - เซสชันเธรดสืบทอดการเลือก `/model` ระดับเซสชันของช่องทางแม่เป็นค่าทดแทนเฉพาะโมเดล; การเลือก `/model` ภายในเธรดยังคงมีลำดับความสำคัญสูงกว่า และประวัติ transcript ของแม่จะไม่ถูกคัดลอก เว้นแต่เปิดใช้การสืบทอด transcript. + - `channels.discord.thread.inheritParent` (ค่าเริ่มต้น `false`) เลือกให้ auto-thread ใหม่เริ่มต้นจาก transcript ของแม่ การแทนที่รายบัญชีอยู่ใต้ `channels.discord.accounts..thread.inheritParent`. + - รีแอ็กชันของเครื่องมือข้อความสามารถระบุเป้าหมาย DM แบบ `user:` ได้. + - `guilds..channels..requireMention: false` จะถูกคงไว้ระหว่าง fallback การเปิดใช้งานในขั้นตอบกลับ. - หัวข้อช่องทางถูกฉีดเข้าเป็นบริบทที่ **ไม่น่าเชื่อถือ** Allowlists จำกัดว่าใครสามารถกระตุ้นเอเจนต์ได้ ไม่ใช่ขอบเขตการปกปิดบริบทเสริมทั้งหมด + หัวข้อช่องทางจะถูกฉีดเป็นบริบทที่ **ไม่น่าเชื่อถือ** allowlist ควบคุมว่าใครสามารถเรียกเอเจนต์ได้ ไม่ใช่ขอบเขตการปกปิดบริบทเสริมทั้งหมด. - - Discord สามารถผูกเธรดกับเป้าหมายเซสชันเพื่อให้ข้อความติดตามผลในเธรดนั้นยังคงถูกกำหนดเส้นทางไปยังเซสชันเดิม (รวมถึงเซสชัน subagent) + + Discord สามารถผูกเธรดกับเป้าหมายเซสชัน เพื่อให้ข้อความติดตามผลในเธรดนั้นยังคงถูกส่งไปยังเซสชันเดียวกัน (รวมถึงเซสชัน subagent). คำสั่ง: - `/focus ` ผูกเธรดปัจจุบัน/ใหม่กับเป้าหมาย subagent/เซสชัน - - `/unfocus` นำการผูกเธรดปัจจุบันออก - - `/agents` แสดง run ที่ใช้งานอยู่และสถานะการผูก - - `/session idle ` ตรวจสอบ/อัปเดตการ unfocus อัตโนมัติเมื่อไม่มีการใช้งานสำหรับการผูกที่ focus อยู่ - - `/session max-age ` ตรวจสอบ/อัปเดตอายุสูงสุดแบบบังคับสำหรับการผูกที่ focus อยู่ + - `/unfocus` ลบการผูกเธรดปัจจุบัน + - `/agents` แสดง run ที่ทำงานอยู่และสถานะการผูก + - `/session idle ` ตรวจสอบ/อัปเดตการยกเลิกโฟกัสอัตโนมัติเมื่อไม่มีความเคลื่อนไหวสำหรับการผูกที่โฟกัสอยู่ + - `/session max-age ` ตรวจสอบ/อัปเดตอายุสูงสุดแบบบังคับสำหรับการผูกที่โฟกัสอยู่ - คอนฟิก: + การกำหนดค่า: ```json5 { @@ -754,23 +778,23 @@ OpenClaw รองรับคอนเทนเนอร์คอมโพเ หมายเหตุ: - - `session.threadBindings.*` ตั้งค่าเริ่มต้นส่วนกลาง - - `channels.discord.threadBindings.*` เขียนทับพฤติกรรม Discord - - `spawnSessions` ควบคุมการสร้าง/ผูกเธรดอัตโนมัติสำหรับ `sessions_spawn({ thread: true })` และการ spawn เธรด ACP ค่าเริ่มต้น: `true` - - `defaultSpawnContext` ควบคุมบริบท subagent แบบเนทีฟสำหรับการ spawn ที่ผูกกับเธรด ค่าเริ่มต้น: `"fork"` - - คีย์ `spawnSubagentSessions`/`spawnAcpSessions` ที่เลิกใช้แล้วจะถูกย้ายโดย `openclaw doctor --fix` - - หากปิดใช้การผูกเธรดสำหรับบัญชีหนึ่ง `/focus` และการดำเนินการผูกเธรดที่เกี่ยวข้องจะไม่พร้อมใช้งาน + - `session.threadBindings.*` ตั้งค่าเริ่มต้นส่วนกลาง. + - `channels.discord.threadBindings.*` แทนที่พฤติกรรม Discord. + - `spawnSessions` ควบคุมการสร้าง/ผูกเธรดอัตโนมัติสำหรับ `sessions_spawn({ thread: true })` และการ spawn เธรด ACP ค่าเริ่มต้น: `true`. + - `defaultSpawnContext` ควบคุมบริบท subagent แบบเนทีฟสำหรับการ spawn ที่ผูกกับเธรด ค่าเริ่มต้น: `"fork"`. + - คีย์ `spawnSubagentSessions`/`spawnAcpSessions` ที่เลิกใช้แล้วจะถูกย้ายโดย `openclaw doctor --fix`. + - หากการผูกเธรดถูกปิดใช้งานสำหรับบัญชี `/focus` และการดำเนินการผูกเธรดที่เกี่ยวข้องจะใช้ไม่ได้. - ดู [Sub-agents](/th/tools/subagents), [เอเจนต์ ACP](/th/tools/acp-agents) และ [อ้างอิงการกำหนดค่า](/th/gateway/configuration-reference) + ดู [Sub-agents](/th/tools/subagents), [เอเจนต์ ACP](/th/tools/acp-agents), และ [อ้างอิงการกำหนดค่า](/th/gateway/configuration-reference). - - สำหรับเวิร์กสเปซ ACP แบบ "เปิดตลอด" ที่เสถียร ให้กำหนดค่าการผูก ACP แบบ typed ระดับบนสุดที่ชี้ไปยังการสนทนา Discord + + สำหรับ workspace ACP ที่เสถียรและ "เปิดตลอดเวลา" ให้กำหนดค่าการผูก ACP แบบ typed ระดับบนสุดที่ชี้ไปยังการสนทนา Discord. - เส้นทางคอนฟิก: + เส้นทางการกำหนดค่า: - - `bindings[]` ที่มี `type: "acp"` และ `match.channel: "discord"` + - `bindings[]` พร้อม `type: "acp"` และ `match.channel: "discord"` ตัวอย่าง: @@ -822,49 +846,49 @@ OpenClaw รองรับคอนเทนเนอร์คอมโพเ หมายเหตุ: - - `/acp spawn codex --bind here` ผูกช่องทางหรือเธรดปัจจุบันไว้ที่เดิมและทำให้ข้อความในอนาคตอยู่ในเซสชัน ACP เดิม ข้อความในเธรดสืบทอดการผูกของช่องทางแม่ - - ในช่องทางหรือเธรดที่ถูกผูกไว้ `/new` และ `/reset` จะรีเซ็ตเซสชัน ACP เดิมที่เดิม การผูกเธรดชั่วคราวสามารถเขียนทับการ resolve เป้าหมายขณะใช้งานอยู่ - - `spawnSessions` จำกัดการสร้าง/ผูกเธรดลูกผ่าน `--thread auto|here` + - `/acp spawn codex --bind here` ผูกช่องทางหรือเธรดปัจจุบันไว้ตรงจุดนั้น และคงข้อความในอนาคตไว้บนเซสชัน ACP เดียวกัน ข้อความในเธรดสืบทอดการผูกช่องทางแม่. + - ในช่องทางหรือเธรดที่ถูกผูกไว้ `/new` และ `/reset` จะรีเซ็ตเซสชัน ACP เดียวกันตรงจุดนั้น การผูกเธรดชั่วคราวสามารถแทนที่การระบุเป้าหมายได้ขณะทำงานอยู่. + - `spawnSessions` ควบคุมการสร้าง/ผูกเธรดลูกผ่าน `--thread auto|here`. - ดู [เอเจนต์ ACP](/th/tools/acp-agents) สำหรับรายละเอียดพฤติกรรมการผูก + ดู [เอเจนต์ ACP](/th/tools/acp-agents) สำหรับรายละเอียดพฤติกรรมการผูก. - - โหมดการแจ้งเตือน reaction รายกิลด์: + + โหมดการแจ้งเตือนรีแอ็กชันรายกิลด์: - `off` - `own` (ค่าเริ่มต้น) - `all` - `allowlist` (ใช้ `guilds..users`) - เหตุการณ์ reaction จะถูกแปลงเป็นเหตุการณ์ระบบและแนบกับเซสชัน Discord ที่ถูกกำหนดเส้นทาง + เหตุการณ์รีแอ็กชันจะถูกแปลงเป็นเหตุการณ์ระบบและแนบกับเซสชัน Discord ที่ถูกกำหนดเส้นทาง. - - `ackReaction` ส่งอีโมจิยืนยันการรับทราบขณะ OpenClaw กำลังประมวลผลข้อความขาเข้า + + `ackReaction` ส่งอีโมจิรับทราบขณะที่ OpenClaw กำลังประมวลผลข้อความขาเข้า. - ลำดับการ resolve: + ลำดับการแก้ค่า: - `channels.discord.accounts..ackReaction` - `channels.discord.ackReaction` - `messages.ackReaction` - - fallback อีโมจิตัวตนเอเจนต์ (`agents.list[].identity.emoji`, ไม่เช่นนั้น "👀") + - fallback อีโมจิของตัวตนเอเจนต์ (`agents.list[].identity.emoji`, มิฉะนั้น "👀") หมายเหตุ: - - Discord รับอีโมจิ unicode หรือชื่ออีโมจิแบบกำหนดเอง - - ใช้ `""` เพื่อปิดใช้ reaction สำหรับช่องทางหรือบัญชี + - Discord รับอีโมจิ Unicode หรือชื่ออีโมจิแบบกำหนดเอง. + - ใช้ `""` เพื่อปิดใช้งานรีแอ็กชันสำหรับช่องทางหรือบัญชี. - - การเขียนคอนฟิกที่เริ่มจากช่องทางเปิดใช้งานเป็นค่าเริ่มต้น + + การเขียนการกำหนดค่าที่เริ่มจากช่องทางเปิดใช้อยู่ตามค่าเริ่มต้น. - สิ่งนี้มีผลต่อ flow `/config set|unset` (เมื่อเปิดใช้ฟีเจอร์คำสั่ง) + สิ่งนี้มีผลต่อ flow `/config set|unset` (เมื่อเปิดใช้ฟีเจอร์คำสั่ง). - ปิดใช้: + ปิดใช้งาน: ```json5 { @@ -879,7 +903,7 @@ OpenClaw รองรับคอนเทนเนอร์คอมโพเ - กำหนดเส้นทางทราฟฟิก WebSocket ของ Discord gateway และการ lookup REST ตอนเริ่มต้น (application ID + การ resolve allowlist) ผ่านพร็อกซี HTTP(S) ด้วย `channels.discord.proxy` + กำหนดเส้นทางทราฟฟิก WebSocket ของ Discord gateway และการค้นหา REST ตอนเริ่มต้น (ID แอปพลิเคชัน + การแก้ค่า allowlist) ผ่านพร็อกซี HTTP(S) ด้วย `channels.discord.proxy`. ```json5 { @@ -891,7 +915,7 @@ OpenClaw รองรับคอนเทนเนอร์คอมโพเ } ``` - การเขียนทับรายบัญชี: + การแทนที่รายบัญชี: ```json5 { @@ -909,8 +933,8 @@ OpenClaw รองรับคอนเทนเนอร์คอมโพเ - - เปิดใช้การ resolve PluralKit เพื่อแมปข้อความที่ถูก proxy กับตัวตนสมาชิกระบบ: + + เปิดใช้การแก้ค่า PluralKit เพื่อแมปข้อความที่ถูกพร็อกซีไปยังตัวตนสมาชิกระบบ: ```json5 { @@ -928,14 +952,14 @@ OpenClaw รองรับคอนเทนเนอร์คอมโพเ หมายเหตุ: - allowlist สามารถใช้ `pk:` - - ชื่อแสดงผลของสมาชิกจะถูกจับคู่ด้วยชื่อ/slug เฉพาะเมื่อ `channels.discord.dangerouslyAllowNameMatching: true` - - การ lookup ใช้ ID ข้อความต้นฉบับและถูกจำกัดด้วยกรอบเวลา - - หาก lookup ล้มเหลว ข้อความที่ถูก proxy จะถูกถือเป็นข้อความบอตและถูกทิ้ง เว้นแต่ `allowBots=true` + - ชื่อที่แสดงของสมาชิกจะถูกจับคู่ตาม name/slug เฉพาะเมื่อ `channels.discord.dangerouslyAllowNameMatching: true` + - การค้นหาใช้ ID ข้อความต้นฉบับและถูกจำกัดด้วยกรอบเวลา + - หากการค้นหาล้มเหลว ข้อความที่ถูกพร็อกซีจะถือเป็นข้อความบอตและถูกทิ้ง เว้นแต่ `allowBots=true` - - ใช้ `mentionAliases` เมื่อเอเจนต์ต้องการ mention ขาออกแบบกำหนดแน่นอนสำหรับผู้ใช้ Discord ที่รู้จัก คีย์คือ handle ที่ไม่มี `@` นำหน้า; ค่าคือ ID ผู้ใช้ Discord handle ที่ไม่รู้จัก, `@everyone`, `@here` และ mention ภายใน code span ของ Markdown จะไม่ถูกเปลี่ยน + + ใช้ `mentionAliases` เมื่อเอเจนต์ต้องการ mention ขาออกแบบกำหนดแน่นอนสำหรับผู้ใช้ Discord ที่รู้จัก คีย์คือ handle ที่ไม่มี `@` นำหน้า; ค่าคือ ID ผู้ใช้ Discord. handle ที่ไม่รู้จัก, `@everyone`, `@here`, และ mention ภายใน code span ของ Markdown จะถูกปล่อยไว้ตามเดิม. ```json5 { @@ -959,9 +983,9 @@ OpenClaw รองรับคอนเทนเนอร์คอมโพเ - การอัปเดต presence จะถูกนำไปใช้เมื่อคุณตั้งค่าฟิลด์สถานะหรือกิจกรรม หรือเมื่อคุณเปิดใช้ auto presence + การอัปเดต presence จะถูกใช้เมื่อคุณตั้งค่าช่อง status หรือ activity หรือเมื่อคุณเปิดใช้ auto presence. - ตัวอย่างเฉพาะสถานะ: + ตัวอย่างเฉพาะ status: ```json5 { @@ -973,7 +997,7 @@ OpenClaw รองรับคอนเทนเนอร์คอมโพเ } ``` - ตัวอย่างกิจกรรม (สถานะแบบกำหนดเองเป็นประเภทกิจกรรมเริ่มต้น): + ตัวอย่าง activity (custom status คือชนิด activity เริ่มต้น): ```json5 { @@ -1000,13 +1024,13 @@ OpenClaw รองรับคอนเทนเนอร์คอมโพเ } ``` - แผนที่ประเภทกิจกรรม: + แผนที่ชนิด activity: - 0: กำลังเล่น - - 1: กำลังสตรีม (ต้องมี `activityUrl`) + - 1: กำลังสตรีม (ต้องใช้ `activityUrl`) - 2: กำลังฟัง - 3: กำลังดู - - 4: กำหนดเอง (ใช้ข้อความกิจกรรมเป็น state ของสถานะ; อีโมจิเป็นตัวเลือก) + - 4: กำหนดเอง (ใช้ข้อความ activity เป็นสถานะ status; อีโมจิเป็นทางเลือก) - 5: กำลังแข่งขัน ตัวอย่าง auto presence (สัญญาณสุขภาพ runtime): @@ -1026,7 +1050,7 @@ OpenClaw รองรับคอนเทนเนอร์คอมโพเ } ``` - auto presence แมปความพร้อมใช้งานของ runtime ไปยังสถานะ Discord: healthy => online, degraded หรือ unknown => idle, exhausted หรือ unavailable => dnd การเขียนทับข้อความแบบเลือกได้: + การแสดงสถานะอัตโนมัติจะจับคู่ความพร้อมใช้งานขณะรันไทม์กับสถานะ Discord: healthy => online, degraded หรือ unknown => idle, exhausted หรือ unavailable => dnd การแทนที่ข้อความแบบเลือกได้: - `autoPresence.healthyText` - `autoPresence.degradedText` @@ -1035,69 +1059,69 @@ OpenClaw รองรับคอนเทนเนอร์คอมโพเ - Discord รองรับการจัดการการอนุมัติด้วยปุ่มใน DM และสามารถเลือกโพสต์ prompt การอนุมัติในช่องทางต้นทางได้ + Discord รองรับการจัดการการอนุมัติด้วยปุ่มใน DM และสามารถโพสต์พรอมต์การอนุมัติในแชนเนลต้นทางได้ตามต้องการ - เส้นทางคอนฟิก: + พาธการกำหนดค่า: - `channels.discord.execApprovals.enabled` - - `channels.discord.execApprovals.approvers` (ไม่บังคับ; ย้อนกลับไปใช้ `commands.ownerAllowFrom` เมื่อเป็นไปได้) + - `channels.discord.execApprovals.approvers` (เลือกได้; ย้อนกลับไปใช้ `commands.ownerAllowFrom` เมื่อทำได้) - `channels.discord.execApprovals.target` (`dm` | `channel` | `both`, ค่าเริ่มต้น: `dm`) - `agentFilter`, `sessionFilter`, `cleanupAfterResolve` - Discord เปิดใช้การอนุมัติ exec แบบเนทีฟโดยอัตโนมัติเมื่อไม่ได้ตั้งค่า `enabled` หรือมีค่าเป็น `"auto"` และสามารถระบุผู้อนุมัติได้อย่างน้อยหนึ่งราย ไม่ว่าจะจาก `execApprovals.approvers` หรือจาก `commands.ownerAllowFrom` Discord จะไม่อนุมานผู้อนุมัติ exec จาก `allowFrom` ของช่อง, `dm.allowFrom` แบบเดิม, หรือ `defaultTo` ของข้อความส่วนตัว ตั้งค่า `enabled: false` เพื่อปิดใช้งาน Discord ในฐานะไคลเอนต์อนุมัติแบบเนทีฟอย่างชัดเจน + Discord จะเปิดใช้งานการอนุมัติ exec แบบเนทีฟโดยอัตโนมัติเมื่อไม่ได้ตั้งค่า `enabled` หรือเป็น `"auto"` และสามารถระบุผู้อนุมัติได้อย่างน้อยหนึ่งราย ไม่ว่าจะจาก `execApprovals.approvers` หรือจาก `commands.ownerAllowFrom` Discord จะไม่อนุมานผู้อนุมัติ exec จาก `allowFrom` ของแชนเนล, `dm.allowFrom` แบบเดิม, หรือ `defaultTo` ของข้อความส่วนตัว ตั้งค่า `enabled: false` เพื่อปิดใช้งาน Discord ในฐานะไคลเอนต์การอนุมัติแบบเนทีฟอย่างชัดเจน - สำหรับคำสั่งกลุ่มที่ละเอียดอ่อนและจำกัดเฉพาะเจ้าของ เช่น `/diagnostics` และ `/export-trajectory` OpenClaw จะส่งพรอมต์อนุมัติและผลลัพธ์สุดท้ายแบบส่วนตัว โดยจะลองใช้ Discord DM ก่อนเมื่อเจ้าของที่เรียกใช้มีเส้นทางเจ้าของของ Discord; หากไม่พร้อมใช้งาน จะย้อนกลับไปใช้เส้นทางเจ้าของแรกที่พร้อมใช้งานจาก `commands.ownerAllowFrom` เช่น Telegram + สำหรับคำสั่งกลุ่มที่ละเอียดอ่อนและจำกัดเฉพาะเจ้าของ เช่น `/diagnostics` และ `/export-trajectory` OpenClaw จะส่งพรอมต์การอนุมัติและผลลัพธ์สุดท้ายแบบส่วนตัว โดยจะลองใช้ Discord DM ก่อนเมื่อเจ้าของที่เรียกใช้มีเส้นทางเจ้าของของ Discord; หากไม่มี จะย้อนกลับไปใช้เส้นทางเจ้าของที่พร้อมใช้งานรายการแรกจาก `commands.ownerAllowFrom` เช่น Telegram - เมื่อ `target` เป็น `channel` หรือ `both` พรอมต์อนุมัติจะปรากฏในช่อง เฉพาะผู้อนุมัติที่ระบุได้แล้วเท่านั้นที่ใช้ปุ่มได้; ผู้ใช้อื่นจะได้รับการปฏิเสธแบบชั่วคราว พรอมต์อนุมัติมีข้อความคำสั่งรวมอยู่ด้วย ดังนั้นให้เปิดใช้การส่งไปยังช่องเฉพาะในช่องที่เชื่อถือได้เท่านั้น หากไม่สามารถอนุมาน ID ช่องจากคีย์เซสชันได้ OpenClaw จะย้อนกลับไปส่งผ่าน DM + เมื่อ `target` เป็น `channel` หรือ `both` พรอมต์การอนุมัติจะมองเห็นได้ในแชนเนล เฉพาะผู้อนุมัติที่ระบุได้เท่านั้นที่ใช้ปุ่มได้; ผู้ใช้อื่นจะได้รับการปฏิเสธแบบ ephemeral พรอมต์การอนุมัติมีข้อความคำสั่งอยู่ด้วย ดังนั้นให้เปิดใช้การส่งไปยังแชนเนลเฉพาะในแชนเนลที่เชื่อถือได้เท่านั้น หากไม่สามารถได้ ID แชนเนลจากคีย์เซสชัน OpenClaw จะย้อนกลับไปส่งผ่าน DM - Discord ยังแสดงปุ่มอนุมัติร่วมที่ช่องแชทอื่นใช้ด้วย อะแดปเตอร์ Discord แบบเนทีฟหลัก ๆ แล้วเพิ่มการกำหนดเส้นทาง DM ของผู้อนุมัติและการกระจายไปยังช่อง - เมื่อมีปุ่มเหล่านั้น ปุ่มดังกล่าวคือ UX การอนุมัติหลัก; OpenClaw - ควรมีคำสั่ง `/approve` แบบแมนนวลเฉพาะเมื่อผลลัพธ์ของเครื่องมือระบุว่า - การอนุมัติผ่านแชทไม่พร้อมใช้งาน หรือการอนุมัติแบบแมนนวลเป็นเส้นทางเดียวเท่านั้น - หากรันไทม์การอนุมัติแบบเนทีฟของ Discord ไม่ทำงาน OpenClaw จะคงพรอมต์ - `/approve ` แบบกำหนดได้ซ้ำในเครื่องให้มองเห็นได้ หาก - รันไทม์ทำงานอยู่แต่ไม่สามารถส่งการ์ดแบบเนทีฟไปยังเป้าหมายใด ๆ ได้ - OpenClaw จะส่งประกาศสำรองในแชทเดียวกันพร้อมคำสั่ง `/approve` - ที่ตรงกันจากการอนุมัติที่ค้างอยู่ + Discord ยังเรนเดอร์ปุ่มการอนุมัติร่วมที่ใช้โดยแชนเนลแชตอื่นด้วย อะแดปเตอร์ Discord แบบเนทีฟเพิ่มการกำหนดเส้นทาง DM ของผู้อนุมัติและการกระจายไปยังแชนเนลเป็นหลัก + เมื่อปุ่มเหล่านั้นมีอยู่ ปุ่มเหล่านั้นคือ UX การอนุมัติหลัก; OpenClaw + ควรรวมคำสั่ง `/approve` แบบแมนนวลเฉพาะเมื่อผลลัพธ์ของเครื่องมือบอกว่า + การอนุมัติผ่านแชตไม่พร้อมใช้งาน หรือการอนุมัติแบบแมนนวลเป็นเส้นทางเดียวเท่านั้น + หากรันไทม์การอนุมัติแบบเนทีฟของ Discord ไม่ได้ทำงาน OpenClaw จะคง + พรอมต์ `/approve ` แบบกำหนดแน่นอนในเครื่องให้มองเห็นได้ หาก + รันไทม์ทำงานอยู่ แต่ไม่สามารถส่งการ์ดแบบเนทีฟไปยังเป้าหมายใดได้ + OpenClaw จะส่งประกาศสำรองในแชตเดียวกันพร้อมคำสั่ง `/approve` + ที่ตรงกันจากการอนุมัติที่รอดำเนินการ - การตรวจสอบสิทธิ์ของ Gateway และการแก้ผลการอนุมัติเป็นไปตามสัญญาไคลเอนต์ Gateway ร่วมกัน (`plugin:` IDs แก้ผ่าน `plugin.approval.resolve`; IDs อื่นแก้ผ่าน `exec.approval.resolve`) การอนุมัติหมดอายุหลังจาก 30 นาทีโดยค่าเริ่มต้น + การรับรองความถูกต้องของ Gateway และการแก้ผลการอนุมัติเป็นไปตามสัญญาไคลเอนต์ Gateway ร่วม (`plugin:` ID จะแก้ผ่าน `plugin.approval.resolve`; ID อื่นผ่าน `exec.approval.resolve`) ตามค่าเริ่มต้น การอนุมัติจะหมดอายุหลังจาก 30 นาที ดู [การอนุมัติ Exec](/th/tools/exec-approvals) -## เครื่องมือและเกตการกระทำ +## เครื่องมือและเกตการดำเนินการ -การกระทำของข้อความ Discord ประกอบด้วยการส่งข้อความ การดูแลช่อง การมอดเดอเรชัน สถานะการแสดงตัว และการกระทำกับเมทาดาทา +การดำเนินการกับข้อความ Discord รวมถึงการส่งข้อความ, การดูแลแชนเนล, การกลั่นกรอง, presence, และการดำเนินการกับเมตาดาต้า ตัวอย่างหลัก: - การส่งข้อความ: `sendMessage`, `readMessages`, `editMessage`, `deleteMessage`, `threadReply` - รีแอ็กชัน: `react`, `reactions`, `emojiList` -- มอดเดอเรชัน: `timeout`, `kick`, `ban` -- สถานะการแสดงตัว: `setPresence` +- การกลั่นกรอง: `timeout`, `kick`, `ban` +- presence: `setPresence` -การกระทำ `event-create` รับพารามิเตอร์ `image` ที่ไม่บังคับ (URL หรือพาธไฟล์ในเครื่อง) เพื่อตั้งค่ารูปภาพหน้าปกของเหตุการณ์ที่กำหนดเวลาไว้ +การดำเนินการ `event-create` รับพารามิเตอร์ `image` แบบเลือกได้ (URL หรือพาธไฟล์ในเครื่อง) เพื่อตั้งค่าภาพหน้าปกของอีเวนต์ที่กำหนดเวลาไว้ -เกตการกระทำอยู่ใต้ `channels.discord.actions.*` +เกตการดำเนินการอยู่ใต้ `channels.discord.actions.*` พฤติกรรมเกตเริ่มต้น: -| กลุ่มการกระทำ | ค่าเริ่มต้น | +| กลุ่มการดำเนินการ | ค่าเริ่มต้น | | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------- | -| reactions, messages, threads, pins, polls, search, memberInfo, roleInfo, channelInfo, channels, voiceStatus, events, stickers, emojiUploads, stickerUploads, permissions | เปิดใช้ | -| roles | ปิดใช้ | -| moderation | ปิดใช้ | -| presence | ปิดใช้ | +| reactions, messages, threads, pins, polls, search, memberInfo, roleInfo, channelInfo, channels, voiceStatus, events, stickers, emojiUploads, stickerUploads, permissions | เปิดใช้งาน | +| roles | ปิดใช้งาน | +| moderation | ปิดใช้งาน | +| presence | ปิดใช้งาน | ## UI Components v2 -OpenClaw ใช้ Discord components v2 สำหรับการอนุมัติ exec และเครื่องหมายข้ามบริบท การกระทำของข้อความ Discord ยังสามารถรับ `components` สำหรับ UI แบบกำหนดเองได้ด้วย (ขั้นสูง; ต้องสร้างเพย์โหลดคอมโพเนนต์ผ่านเครื่องมือ discord) ขณะที่ `embeds` แบบเดิมยังคงพร้อมใช้งาน แต่ไม่แนะนำ +OpenClaw ใช้ Discord components v2 สำหรับการอนุมัติ exec และมาร์กเกอร์ข้ามบริบท การดำเนินการกับข้อความ Discord ยังสามารถรับ `components` สำหรับ UI แบบกำหนดเองได้ด้วย (ขั้นสูง; ต้องสร้างเพย์โหลด component ผ่านเครื่องมือ discord) ขณะที่ `embeds` แบบเดิมยังพร้อมใช้งาน แต่ไม่แนะนำ -- `channels.discord.ui.components.accentColor` ตั้งค่าสีเน้นที่คอนเทนเนอร์คอมโพเนนต์ของ Discord ใช้ (hex) -- ตั้งค่าแยกตามบัญชีด้วย `channels.discord.accounts..ui.components.accentColor` -- `embeds` จะถูกละเว้นเมื่อมี components v2 อยู่ +- `channels.discord.ui.components.accentColor` ตั้งค่าสีเน้นที่ใช้โดยคอนเทนเนอร์ component ของ Discord (hex) +- ตั้งค่าต่อบัญชีด้วย `channels.discord.accounts..ui.components.accentColor` +- `embeds` จะถูกละเว้นเมื่อมี components v2 ตัวอย่าง: @@ -1117,20 +1141,20 @@ OpenClaw ใช้ Discord components v2 สำหรับการอนุม ## เสียง -Discord มีพื้นผิวเสียงสองแบบที่แยกจากกัน: **ช่องเสียง** แบบเรียลไทม์ (การสนทนาต่อเนื่อง) และ **ไฟล์แนบข้อความเสียง** (รูปแบบพรีวิวคลื่นเสียง) Gateway รองรับทั้งสองแบบ +Discord มีพื้นผิวเสียงที่แตกต่างกันสองแบบ: **แชนเนลเสียง** แบบเรียลไทม์ (การสนทนาต่อเนื่อง) และ **ไฟล์แนบข้อความเสียง** (รูปแบบตัวอย่างคลื่นเสียง) Gateway รองรับทั้งสองแบบ -### ช่องเสียง +### แชนเนลเสียง รายการตรวจสอบการตั้งค่า: -1. เปิดใช้ Message Content Intent ใน Discord Developer Portal -2. เปิดใช้ Server Members Intent เมื่อใช้รายการอนุญาตบทบาท/ผู้ใช้ +1. เปิดใช้งาน Message Content Intent ใน Discord Developer Portal +2. เปิดใช้งาน Server Members Intent เมื่อใช้รายการอนุญาตตามบทบาท/ผู้ใช้ 3. เชิญบอทด้วยสโคป `bot` และ `applications.commands` -4. ให้สิทธิ์ Connect, Speak, Send Messages และ Read Message History ในช่องเสียงเป้าหมาย -5. เปิดใช้คำสั่งแบบเนทีฟ (`commands.native` หรือ `channels.discord.commands.native`) +4. ให้สิทธิ์ Connect, Speak, Send Messages, และ Read Message History ในแชนเนลเสียงเป้าหมาย +5. เปิดใช้งานคำสั่งเนทีฟ (`commands.native` หรือ `channels.discord.commands.native`) 6. กำหนดค่า `channels.discord.voice` -ใช้ `/vc join|leave|status` เพื่อควบคุมเซสชัน คำสั่งนี้ใช้เอเจนต์เริ่มต้นของบัญชีและทำตามกฎรายการอนุญาตและนโยบายกลุ่มเดียวกับคำสั่ง Discord อื่น ๆ +ใช้ `/vc join|leave|status` เพื่อควบคุมเซสชัน คำสั่งนี้ใช้เอเจนต์เริ่มต้นของบัญชี และปฏิบัติตามกฎรายการอนุญาตและนโยบายกลุ่มเดียวกับคำสั่ง Discord อื่น ```bash /vc join channel: @@ -1169,33 +1193,33 @@ Discord มีพื้นผิวเสียงสองแบบที่แ หมายเหตุ: -- `voice.tts` จะแทนที่ `messages.tts` สำหรับการเล่นเสียงเท่านั้น -- `voice.model` จะแทนที่ LLM ที่ใช้สำหรับการตอบกลับช่องเสียง Discord เท่านั้น ปล่อยไว้ไม่ตั้งค่าเพื่อสืบทอดโมเดลเอเจนต์ที่กำหนดเส้นทางไว้ +- `voice.tts` แทนที่ `messages.tts` สำหรับการเล่นเสียงเท่านั้น +- `voice.model` แทนที่ LLM ที่ใช้สำหรับคำตอบในแชนเนลเสียง Discord เท่านั้น ปล่อยให้ไม่ตั้งค่าเพื่อสืบทอดโมเดลเอเจนต์ที่ถูกกำหนดเส้นทางมา - STT ใช้ `tools.media.audio`; `voice.model` ไม่มีผลต่อการถอดเสียง -- การแทนที่ `systemPrompt` ของ Discord รายช่องจะมีผลกับรอบถอดเสียงของช่องเสียงนั้น -- รอบถอดเสียงจะอนุมานสถานะเจ้าของจาก `allowFrom` ของ Discord (หรือ `dm.allowFrom`); ผู้พูดที่ไม่ใช่เจ้าของไม่สามารถเข้าถึงเครื่องมือเฉพาะเจ้าของได้ (เช่น `gateway` และ `cron`) -- เสียง Discord เป็นแบบเลือกเปิดสำหรับคอนฟิกข้อความเท่านั้น; ตั้งค่า `channels.discord.voice.enabled=true` (หรือคงบล็อก `channels.discord.voice` ที่มีอยู่) เพื่อเปิดใช้คำสั่ง `/vc`, รันไทม์เสียง และ Gateway intent `GuildVoiceStates` -- `channels.discord.intents.voiceStates` สามารถแทนที่การสมัครใช้งาน voice-state intent ได้อย่างชัดเจน ปล่อยไว้ไม่ตั้งค่าเพื่อให้ intent เป็นไปตามการเปิดใช้เสียงที่มีผลจริง +- การแทนที่ `systemPrompt` ของ Discord ต่อแชนเนลจะใช้กับรอบ transcript เสียงสำหรับแชนเนลเสียงนั้น +- รอบ transcript เสียงได้สถานะเจ้าของจาก `allowFrom` ของ Discord (หรือ `dm.allowFrom`); ผู้พูดที่ไม่ใช่เจ้าของไม่สามารถเข้าถึงเครื่องมือเฉพาะเจ้าของได้ (เช่น `gateway` และ `cron`) +- เสียง Discord เป็นแบบ opt-in สำหรับการกำหนดค่าแบบข้อความเท่านั้น; ตั้งค่า `channels.discord.voice.enabled=true` (หรือคงบล็อก `channels.discord.voice` ที่มีอยู่) เพื่อเปิดใช้งานคำสั่ง `/vc`, รันไทม์เสียง, และ Gateway intent `GuildVoiceStates` +- `channels.discord.intents.voiceStates` สามารถแทนที่การสมัครรับ intent สถานะเสียงได้อย่างชัดเจน ปล่อยให้ไม่ตั้งค่าเพื่อให้ intent เป็นไปตามการเปิดใช้งานเสียงที่มีผลจริง - `voice.daveEncryption` และ `voice.decryptionFailureTolerance` ส่งต่อไปยังตัวเลือก join ของ `@discordjs/voice` - ค่าเริ่มต้นของ `@discordjs/voice` คือ `daveEncryption=true` และ `decryptionFailureTolerance=24` หากไม่ได้ตั้งค่า -- `voice.connectTimeoutMs` ควบคุมการรอ Ready เริ่มต้นของ `@discordjs/voice` สำหรับ `/vc join` และความพยายามเข้าร่วมอัตโนมัติ ค่าเริ่มต้น: `30000` +- `voice.connectTimeoutMs` ควบคุมการรอ Ready เริ่มต้นของ `@discordjs/voice` สำหรับความพยายาม `/vc join` และการเข้าร่วมอัตโนมัติ ค่าเริ่มต้น: `30000` - `voice.reconnectGraceMs` ควบคุมระยะเวลาที่ OpenClaw รอให้เซสชันเสียงที่ตัดการเชื่อมต่อเริ่มเชื่อมต่อใหม่ก่อนทำลายเซสชันนั้น ค่าเริ่มต้น: `15000` -- OpenClaw ยังเฝ้าดูความล้มเหลวในการถอดรหัสฝั่งรับและกู้คืนอัตโนมัติโดยออกจากช่องเสียงแล้วเข้าร่วมใหม่หลังเกิดความล้มเหลวซ้ำ ๆ ในช่วงเวลาสั้น ๆ -- หากบันทึกฝั่งรับแสดง `DecryptionFailed(UnencryptedWhenPassthroughDisabled)` ซ้ำ ๆ หลังอัปเดต ให้รวบรวมรายงาน dependency และบันทึก บรรทัด `@discordjs/voice` ที่รวมมาแล้วมี upstream padding fix จาก discord.js PR #11449 ซึ่งปิด discord.js issue #11419 แล้ว +- OpenClaw ยังเฝ้าดูความล้มเหลวในการถอดรหัสฝั่งรับ และกู้คืนอัตโนมัติด้วยการออกจาก/เข้าร่วมแชนเนลเสียงใหม่หลังเกิดความล้มเหลวซ้ำในช่วงเวลาสั้น +- หากบันทึกฝั่งรับแสดง `DecryptionFailed(UnencryptedWhenPassthroughDisabled)` ซ้ำหลังอัปเดต ให้รวบรวมรายงาน dependency และบันทึก บรรทัด `@discordjs/voice` ที่บันเดิลมามีการแก้ไข padding จาก upstream ใน discord.js PR #11449 ซึ่งปิด discord.js issue #11419 แล้ว -ไปป์ไลน์ช่องเสียง: +ไปป์ไลน์แชนเนลเสียง: -- การจับ Discord PCM จะถูกแปลงเป็นไฟล์ WAV ชั่วคราว +- การจับเสียง PCM จาก Discord ถูกแปลงเป็นไฟล์ WAV ชั่วคราว - `tools.media.audio` จัดการ STT เช่น `openai/gpt-4o-mini-transcribe` -- ทรานสคริปต์ถูกส่งผ่านทางเข้าและการกำหนดเส้นทางของ Discord ขณะที่ LLM สำหรับตอบกลับทำงานด้วยนโยบายเอาต์พุตเสียงที่ซ่อนเครื่องมือ `tts` ของเอเจนต์และขอให้ส่งคืนเป็นข้อความ เพราะเสียง Discord เป็นเจ้าของการเล่น TTS สุดท้าย -- เมื่อกำหนด `voice.model` ไว้ จะแทนที่เฉพาะ LLM สำหรับตอบกลับในรอบช่องเสียงนี้ -- `voice.tts` จะถูกผสานทับ `messages.tts`; เสียงที่ได้จะถูกเล่นในช่องที่เข้าร่วมอยู่ +- transcript ถูกส่งผ่าน ingress และการกำหนดเส้นทางของ Discord ขณะที่ LLM สำหรับคำตอบทำงานด้วยนโยบายเอาต์พุตเสียงที่ซ่อนเครื่องมือ `tts` ของเอเจนต์และขอข้อความที่ส่งคืน เพราะเสียง Discord เป็นเจ้าของการเล่น TTS ขั้นสุดท้าย +- `voice.model` เมื่อถูกตั้งค่า จะแทนที่เฉพาะ LLM สำหรับคำตอบในรอบแชนเนลเสียงนี้ +- `voice.tts` จะถูกผสานทับ `messages.tts`; เสียงที่ได้จะถูกเล่นในแชนเนลที่เข้าร่วมอยู่ -ข้อมูลประจำตัวถูกแก้แยกตามคอมโพเนนต์: การตรวจสอบสิทธิ์เส้นทาง LLM สำหรับ `voice.model`, การตรวจสอบสิทธิ์ STT สำหรับ `tools.media.audio`, และการตรวจสอบสิทธิ์ TTS สำหรับ `messages.tts`/`voice.tts` +ข้อมูลประจำตัวจะถูกแก้ต่อ component: การรับรองความถูกต้องของเส้นทาง LLM สำหรับ `voice.model`, การรับรองความถูกต้องของ STT สำหรับ `tools.media.audio`, และการรับรองความถูกต้องของ TTS สำหรับ `messages.tts`/`voice.tts` ### ข้อความเสียง -ข้อความเสียง Discord แสดงพรีวิวคลื่นเสียงและต้องใช้เสียง OGG/Opus OpenClaw สร้างคลื่นเสียงให้อัตโนมัติ แต่ต้องมี `ffmpeg` และ `ffprobe` บนโฮสต์ Gateway เพื่อตรวจสอบและแปลง +ข้อความเสียง Discord แสดงตัวอย่างคลื่นเสียงและต้องใช้เสียง OGG/Opus OpenClaw สร้างคลื่นเสียงให้อัตโนมัติ แต่ต้องมี `ffmpeg` และ `ffprobe` บนโฮสต์ Gateway เพื่อตรวจสอบและแปลง - ระบุ **พาธไฟล์ในเครื่อง** (URL จะถูกปฏิเสธ) - ละเว้นเนื้อหาข้อความ (Discord ปฏิเสธข้อความ + ข้อความเสียงในเพย์โหลดเดียวกัน) @@ -1208,20 +1232,20 @@ message(action="send", channel="discord", target="channel:123", path="/path/to/a ## การแก้ไขปัญหา - + - - เปิดใช้ Message Content Intent - - เปิดใช้ Server Members Intent เมื่อคุณพึ่งพาการระบุผู้ใช้/สมาชิก - - รีสตาร์ท Gateway หลังเปลี่ยน intents + - เปิดใช้งาน Message Content Intent + - เปิดใช้งาน Server Members Intent เมื่อคุณพึ่งพาการแก้ข้อมูลผู้ใช้/สมาชิก + - รีสตาร์ท gateway หลังเปลี่ยน intents - + - ตรวจสอบ `groupPolicy` - - ตรวจสอบรายการอนุญาต guild ใต้ `channels.discord.guilds` - - หากมีแมป `channels` ของ guild จะอนุญาตเฉพาะช่องที่ระบุไว้เท่านั้น - - ตรวจสอบพฤติกรรม `requireMention` และรูปแบบการกล่าวถึง + - ตรวจสอบรายการอนุญาตของ guild ใต้ `channels.discord.guilds` + - หากมีแผนที่ `channels` ของ guild จะอนุญาตเฉพาะแชนเนลที่ระบุไว้เท่านั้น + - ตรวจสอบพฤติกรรม `requireMention` และรูปแบบการ mention การตรวจสอบที่มีประโยชน์: @@ -1233,29 +1257,29 @@ openclaw logs --follow - + สาเหตุที่พบบ่อย: - - `groupPolicy="allowlist"` โดยไม่มีรายการอนุญาต guild/channel ที่ตรงกัน - - กำหนดค่า `requireMention` ผิดตำแหน่ง (ต้องอยู่ใต้ `channels.discord.guilds` หรือรายการช่อง) + - `groupPolicy="allowlist"` โดยไม่มีรายการอนุญาตของ guild/channel ที่ตรงกัน + - กำหนดค่า `requireMention` ผิดตำแหน่ง (ต้องอยู่ใต้ `channels.discord.guilds` หรือรายการแชนเนล) - ผู้ส่งถูกบล็อกโดยรายการอนุญาต `users` ของ guild/channel - + บันทึกทั่วไป: - `Slow listener detected ...` - `stuck session: sessionKey=agent:...:discord:... state=processing ...` - ปุ่มปรับแต่งคิว Gateway ของ Discord: + ปุ่มปรับคิว Gateway ของ Discord: - บัญชีเดียว: `channels.discord.eventQueue.listenerTimeout` - หลายบัญชี: `channels.discord.accounts..eventQueue.listenerTimeout` - ค่านี้ควบคุมเฉพาะงาน listener ของ Gateway Discord ไม่ใช่อายุการทำงานของรอบเอเจนต์ - Discord ไม่ใช้การหมดเวลาที่ช่องเป็นเจ้าของกับรอบเอเจนต์ที่อยู่ในคิว ตัวฟังข้อความจะส่งต่องานทันที และการรัน Discord ที่เข้าคิวจะรักษาลำดับรายเซสชันไว้จนกว่าวงจรชีวิตของเซสชัน/เครื่องมือ/รันไทม์จะเสร็จสมบูรณ์หรือยกเลิกงาน + Discord จะไม่ใช้ timeout ที่เป็นของแชนเนลกับรอบเอเจนต์ที่อยู่ในคิว Message listeners จะส่งต่อทันที และการทำงาน Discord ที่อยู่ในคิวจะรักษาลำดับต่อเซสชันไว้จนกว่าวงจรชีวิตของเซสชัน/เครื่องมือ/รันไทม์จะเสร็จสิ้นหรือยกเลิกงาน ```json5 { @@ -1275,38 +1299,38 @@ openclaw logs --follow - - OpenClaw ดึงข้อมูลเมทาดาทา `/gateway/bot` ของ Discord ก่อนเชื่อมต่อ ความล้มเหลวชั่วคราวจะย้อนกลับไปใช้ URL Gateway เริ่มต้นของ Discord และถูกจำกัดอัตราในบันทึก + + OpenClaw ดึงข้อมูลเมตา `/gateway/bot` ของ Discord ก่อนเชื่อมต่อ ความล้มเหลวชั่วคราวจะย้อนกลับไปใช้ URL Gateway เริ่มต้นของ Discord และถูกจำกัดอัตราในบันทึก - ปุ่มปรับแต่งการหมดเวลาเมทาดาทา: + ตัวปรับค่าหมดเวลาของข้อมูลเมตา: - บัญชีเดียว: `channels.discord.gatewayInfoTimeoutMs` - หลายบัญชี: `channels.discord.accounts..gatewayInfoTimeoutMs` - - ค่า env สำรองเมื่อไม่ได้ตั้งค่าคอนฟิก: `OPENCLAW_DISCORD_GATEWAY_INFO_TIMEOUT_MS` + - env fallback เมื่อไม่ได้ตั้งค่าคอนฟิก: `OPENCLAW_DISCORD_GATEWAY_INFO_TIMEOUT_MS` - ค่าเริ่มต้น: `30000` (30 วินาที), สูงสุด: `120000` - OpenClaw รอเหตุการณ์ `READY` ของ Gateway ของ Discord ระหว่างการเริ่มต้นและหลังจากการเชื่อมต่อใหม่ขณะรันไทม์ การตั้งค่าหลายบัญชีที่มีการหน่วงเวลาเริ่มต้นทีละบัญชีอาจต้องใช้ช่วงเวลา READY ตอนเริ่มต้นที่นานกว่าค่าเริ่มต้น + OpenClaw รอเหตุการณ์ `READY` ของ Gateway Discord ระหว่างเริ่มต้นระบบและหลังการเชื่อมต่อใหม่ขณะทำงาน การตั้งค่าหลายบัญชีที่มีการหน่วงเวลาเริ่มต้นแบบเหลื่อมกันอาจต้องใช้ช่วงเวลา READY ตอนเริ่มต้นที่ยาวกว่าค่าเริ่มต้น - ปุ่มปรับค่าการหมดเวลา READY: + ตัวปรับค่าหมดเวลา READY: - - การเริ่มต้นแบบบัญชีเดียว: `channels.discord.gatewayReadyTimeoutMs` - - การเริ่มต้นแบบหลายบัญชี: `channels.discord.accounts..gatewayReadyTimeoutMs` - - ค่า env สำรองสำหรับการเริ่มต้นเมื่อไม่ได้ตั้งค่าคอนฟิก: `OPENCLAW_DISCORD_READY_TIMEOUT_MS` - - ค่าเริ่มต้นสำหรับการเริ่มต้น: `15000` (15 วินาที), สูงสุด: `120000` - - รันไทม์แบบบัญชีเดียว: `channels.discord.gatewayRuntimeReadyTimeoutMs` - - รันไทม์แบบหลายบัญชี: `channels.discord.accounts..gatewayRuntimeReadyTimeoutMs` - - ค่า env สำรองสำหรับรันไทม์เมื่อไม่ได้ตั้งค่าคอนฟิก: `OPENCLAW_DISCORD_RUNTIME_READY_TIMEOUT_MS` - - ค่าเริ่มต้นสำหรับรันไทม์: `30000` (30 วินาที), สูงสุด: `120000` + - เริ่มต้นแบบบัญชีเดียว: `channels.discord.gatewayReadyTimeoutMs` + - เริ่มต้นแบบหลายบัญชี: `channels.discord.accounts..gatewayReadyTimeoutMs` + - startup env fallback เมื่อไม่ได้ตั้งค่าคอนฟิก: `OPENCLAW_DISCORD_READY_TIMEOUT_MS` + - ค่าเริ่มต้นตอนเริ่มต้น: `15000` (15 วินาที), สูงสุด: `120000` + - ขณะทำงานแบบบัญชีเดียว: `channels.discord.gatewayRuntimeReadyTimeoutMs` + - ขณะทำงานแบบหลายบัญชี: `channels.discord.accounts..gatewayRuntimeReadyTimeoutMs` + - runtime env fallback เมื่อไม่ได้ตั้งค่าคอนฟิก: `OPENCLAW_DISCORD_RUNTIME_READY_TIMEOUT_MS` + - ค่าเริ่มต้นขณะทำงาน: `30000` (30 วินาที), สูงสุด: `120000` - - การตรวจสอบสิทธิ์ด้วย `channels status --probe` ใช้งานได้เฉพาะกับ ID ช่องแบบตัวเลขเท่านั้น + + การตรวจสอบสิทธิ์ของ `channels status --probe` ใช้ได้เฉพาะกับ ID ช่องที่เป็นตัวเลขเท่านั้น - หากคุณใช้คีย์แบบ slug การจับคู่ขณะรันไทม์อาจยังใช้งานได้ แต่ probe ไม่สามารถตรวจสอบสิทธิ์ได้ครบถ้วน + หากคุณใช้คีย์แบบ slug การจับคู่ขณะทำงานยังสามารถทำงานได้ แต่ probe ไม่สามารถตรวจสอบสิทธิ์ได้ครบถ้วน @@ -1314,15 +1338,15 @@ openclaw logs --follow - ปิดใช้งาน DM: `channels.discord.dm.enabled=false` - ปิดใช้งานนโยบาย DM: `channels.discord.dmPolicy="disabled"` (แบบเดิม: `channels.discord.dm.policy`) - - กำลังรออนุมัติการจับคู่ในโหมด `pairing` + - กำลังรอการอนุมัติการจับคู่ในโหมด `pairing` - + โดยค่าเริ่มต้น ข้อความที่เขียนโดยบอตจะถูกละเว้น - หากคุณตั้งค่า `channels.discord.allowBots=true` ให้ใช้กฎการกล่าวถึงและ allowlist ที่เข้มงวดเพื่อหลีกเลี่ยงพฤติกรรมแบบลูป - แนะนำให้ใช้ `channels.discord.allowBots="mentions"` เพื่อรับเฉพาะข้อความจากบอตที่กล่าวถึงบอตนี้เท่านั้น + หากคุณตั้งค่า `channels.discord.allowBots=true` ให้ใช้กฎ mention และ allowlist ที่เข้มงวดเพื่อหลีกเลี่ยงพฤติกรรมลูป + แนะนำให้ใช้ `channels.discord.allowBots="mentions"` เพื่อรับเฉพาะข้อความบอตที่กล่าวถึงบอตเท่านั้น ```json5 { @@ -1351,44 +1375,44 @@ openclaw logs --follow - - ใช้ OpenClaw เวอร์ชันปัจจุบันอยู่เสมอ (`openclaw update`) เพื่อให้มีตรรกะกู้คืนการรับเสียงของ Discord + - อัปเดต OpenClaw ให้เป็นปัจจุบันอยู่เสมอ (`openclaw update`) เพื่อให้มีตรรกะการกู้คืนการรับเสียงของ Discord - ยืนยันว่า `channels.discord.voice.daveEncryption=true` (ค่าเริ่มต้น) - เริ่มจาก `channels.discord.voice.decryptionFailureTolerance=24` (ค่าเริ่มต้นจาก upstream) และปรับเฉพาะเมื่อจำเป็น - ดูบันทึกสำหรับ: - `discord voice: DAVE decrypt failures detected` - `discord voice: repeated decrypt failures; attempting rejoin` - - หากยังล้มเหลวต่อหลังจากเข้าร่วมใหม่โดยอัตโนมัติ ให้รวบรวมบันทึกและเปรียบเทียบกับประวัติการรับ DAVE จาก upstream ใน [discord.js #11419](https://github.com/discordjs/discord.js/issues/11419) และ [discord.js #11449](https://github.com/discordjs/discord.js/pull/11449) + - หากความล้มเหลวยังคงเกิดขึ้นหลังจากเข้าร่วมใหม่โดยอัตโนมัติ ให้รวบรวมบันทึกและเปรียบเทียบกับประวัติการรับ DAVE จาก upstream ใน [discord.js #11419](https://github.com/discordjs/discord.js/issues/11419) และ [discord.js #11449](https://github.com/discordjs/discord.js/pull/11449) -## ข้อมูลอ้างอิงการกำหนดค่า +## เอกสารอ้างอิงการตั้งค่า -ข้อมูลอ้างอิงหลัก: [ข้อมูลอ้างอิงการกำหนดค่า - Discord](/th/gateway/config-channels#discord) +เอกสารอ้างอิงหลัก: [เอกสารอ้างอิงการตั้งค่า - Discord](/th/gateway/config-channels#discord) - + -- การเริ่มต้น/auth: `enabled`, `token`, `accounts.*`, `allowBots` +- การเริ่มต้น/การยืนยันตัวตน: `enabled`, `token`, `accounts.*`, `allowBots` - นโยบาย: `groupPolicy`, `dm.*`, `guilds.*`, `guilds.*.channels.*` - คำสั่ง: `commands.native`, `commands.useAccessGroups`, `configWrites`, `slashCommand.*` -- คิวเหตุการณ์: `eventQueue.listenerTimeout` (งบเวลา listener), `eventQueue.maxQueueSize`, `eventQueue.maxConcurrency` +- คิวเหตุการณ์: `eventQueue.listenerTimeout` (งบประมาณ listener), `eventQueue.maxQueueSize`, `eventQueue.maxConcurrency` - Gateway: `gatewayInfoTimeoutMs`, `gatewayReadyTimeoutMs`, `gatewayRuntimeReadyTimeoutMs` - การตอบกลับ/ประวัติ: `replyToMode`, `historyLimit`, `dmHistoryLimit`, `dms.*.historyLimit` -- การส่งข้อความ: `textChunkLimit`, `chunkMode`, `maxLinesPerMessage` -- การสตรีม: `streaming` (alias เดิม: `streamMode`), `streaming.preview.toolProgress`, `draftChunk`, `blockStreaming`, `blockStreamingCoalesce` -- สื่อ/การลองใหม่: `mediaMaxMb` (จำกัดการอัปโหลดออกไปยัง Discord, ค่าเริ่มต้น `100MB`), `retry` +- การส่งมอบ: `textChunkLimit`, `chunkMode`, `maxLinesPerMessage` +- การสตรีม: `streaming` (นามแฝงแบบเดิม: `streamMode`), `streaming.preview.toolProgress`, `draftChunk`, `blockStreaming`, `blockStreamingCoalesce` +- สื่อ/การลองใหม่: `mediaMaxMb` (จำกัดการอัปโหลดขาออกของ Discord, ค่าเริ่มต้น `100MB`), `retry` - การดำเนินการ: `actions.*` -- สถานะออนไลน์: `activity`, `status`, `activityType`, `activityUrl` +- presence: `activity`, `status`, `activityType`, `activityUrl` - UI: `ui.components.accentColor` -- ฟีเจอร์: `threadBindings`, `bindings[]` ระดับบน (`type: "acp"`), `pluralkit`, `execApprovals`, `intents`, `agentComponents`, `heartbeat`, `responsePrefix` +- ฟีเจอร์: `threadBindings`, `bindings[]` ระดับบนสุด (`type: "acp"`), `pluralkit`, `execApprovals`, `intents`, `agentComponents`, `heartbeat`, `responsePrefix` -## ความปลอดภัยและการปฏิบัติงาน +## ความปลอดภัยและการปฏิบัติการ -- ปฏิบัติต่อโทเคนบอตเป็นความลับ (แนะนำให้ใช้ `DISCORD_BOT_TOKEN` ในสภาพแวดล้อมที่มีการควบคุม) +- ถือว่าโทเค็นบอตเป็นความลับ (แนะนำให้ใช้ `DISCORD_BOT_TOKEN` ในสภาพแวดล้อมที่มีการกำกับดูแล) - ให้สิทธิ์ Discord เท่าที่จำเป็นน้อยที่สุด -- หากสถานะการ deploy คำสั่ง/สถานะค้าง ให้รีสตาร์ต Gateway และตรวจสอบอีกครั้งด้วย `openclaw channels status --probe` +- หากการ deploy/สถานะของคำสั่งล้าสมัย ให้รีสตาร์ต Gateway และตรวจสอบอีกครั้งด้วย `openclaw channels status --probe` ## ที่เกี่ยวข้อง @@ -1406,9 +1430,9 @@ openclaw logs --follow โมเดลภัยคุกคามและการเสริมความปลอดภัย - แมป guild และช่องกับเอเจนต์ + แมปกิลด์และช่องไปยังเอเจนต์ - พฤติกรรมคำสั่งแบบเนทีฟ + พฤติกรรมคำสั่งเนทีฟ diff --git a/docs/th/channels/slack.md b/docs/th/channels/slack.md index 7cdc81742..7ed301fd7 100644 --- a/docs/th/channels/slack.md +++ b/docs/th/channels/slack.md @@ -1,47 +1,47 @@ --- read_when: - - การตั้งค่า Slack หรือการดีบักโหมดซ็อกเก็ต/HTTP ของ Slack -summary: การตั้งค่า Slack และพฤติกรรมระหว่างการทำงาน (โหมดซ็อกเก็ต + URL คำขอ HTTP) + - การตั้งค่า Slack หรือการดีบักโหมด socket/HTTP ของ Slack +summary: การตั้งค่า Slack และพฤติกรรมขณะรัน (โหมด Socket + URL ของคำขอ HTTP) title: Slack x-i18n: - generated_at: "2026-05-04T02:22:24Z" + generated_at: "2026-05-04T07:02:53Z" model: gpt-5.5 provider: openai - source_hash: 2be45f03511a64373b1f4316c59800eeeef8baccb4c00454b49999258b2e546b + source_hash: d4a91fc1ae5f1e03f714308be54e164ef204809e74efabed8dc75c3035c14228 source_path: channels/slack.md workflow: 16 --- -พร้อมใช้งานระดับโปรดักชันสำหรับ DM และช่องผ่านการผสานรวมแอป Slack โหมดเริ่มต้นคือ Socket Mode และรองรับ HTTP Request URLs ด้วย +พร้อมใช้งานระดับโปรดักชันสำหรับ DM และช่องผ่านการผสานรวม Slack app โหมดเริ่มต้นคือ Socket Mode และยังรองรับ HTTP Request URLs ด้วย - - Slack DM ใช้โหมดจับคู่เป็นค่าเริ่มต้น + + Slack DM ใช้โหมดการจับคู่เป็นค่าเริ่มต้น - - พฤติกรรมคำสั่งแบบเนทีฟและแคตตาล็อกคำสั่ง + + ลักษณะการทำงานของคำสั่งแบบเนทีฟและแค็ตตาล็อกคำสั่ง - - การวินิจฉัยข้ามช่องและคู่มือการซ่อมแซม + + การวินิจฉัยข้ามช่องและคู่มือปฏิบัติการซ่อมแซม -## การตั้งค่าแบบรวดเร็ว +## ตั้งค่าอย่างรวดเร็ว - + - - ในการตั้งค่าแอป Slack ให้กดปุ่ม **[Create New App](https://api.slack.com/apps/new)**: + + ในการตั้งค่า Slack app ให้กดปุ่ม **[Create New App](https://api.slack.com/apps/new)**: - - เลือก **from a manifest** และเลือกเวิร์กสเปซสำหรับแอปของคุณ - - วาง [แมนิเฟสต์ตัวอย่าง](#manifest-and-scope-checklist) ด้านล่าง แล้วดำเนินการต่อเพื่อสร้าง - - สร้าง **App-Level Token** (`xapp-...`) ที่มี `connections:write` + - เลือก **from a manifest** และเลือก workspace สำหรับแอปของคุณ + - วาง [manifest ตัวอย่าง](#manifest-and-scope-checklist) ด้านล่างและดำเนินการต่อเพื่อสร้าง + - สร้าง **App-Level Token** (`xapp-...`) พร้อม `connections:write` - ติดตั้งแอปและคัดลอก **Bot Token** (`xoxb-...`) ที่แสดง - + การตั้งค่า SecretRef ที่แนะนำ: @@ -64,7 +64,7 @@ openclaw config patch --file ./slack.socket.patch.json5 --dry-run openclaw config patch --file ./slack.socket.patch.json5 ``` - ทางเลือกสำรอง Env (เฉพาะบัญชีเริ่มต้น): + Env สำรอง (เฉพาะบัญชีเริ่มต้นเท่านั้น): ```bash SLACK_APP_TOKEN=xapp-... @@ -73,7 +73,7 @@ SLACK_BOT_TOKEN=xoxb-... - + ```bash openclaw gateway @@ -86,17 +86,17 @@ openclaw gateway - - ในการตั้งค่าแอป Slack ให้กดปุ่ม **[Create New App](https://api.slack.com/apps/new)**: + + ในการตั้งค่า Slack app ให้กดปุ่ม **[Create New App](https://api.slack.com/apps/new)**: - - เลือก **from a manifest** และเลือกเวิร์กสเปซสำหรับแอปของคุณ - - วาง [แมนิเฟสต์ตัวอย่าง](#manifest-and-scope-checklist) และอัปเดต URL ก่อนสร้าง + - เลือก **from a manifest** และเลือก workspace สำหรับแอปของคุณ + - วาง [manifest ตัวอย่าง](#manifest-and-scope-checklist) และอัปเดต URL ก่อนสร้าง - บันทึก **Signing Secret** สำหรับการตรวจสอบคำขอ - ติดตั้งแอปและคัดลอก **Bot Token** (`xoxb-...`) ที่แสดง - + การตั้งค่า SecretRef ที่แนะนำ: @@ -121,14 +121,14 @@ openclaw config patch --file ./slack.http.patch.json5 ``` - ใช้เส้นทาง Webhook ที่ไม่ซ้ำกันสำหรับ HTTP แบบหลายบัญชี + ใช้ webhook path ที่ไม่ซ้ำกันสำหรับ HTTP หลายบัญชี - กำหนด `webhookPath` แยกกันให้แต่ละบัญชี (ค่าเริ่มต้น `/slack/events`) เพื่อไม่ให้การลงทะเบียนชนกัน + กำหนด `webhookPath` ที่แตกต่างกันให้แต่ละบัญชี (ค่าเริ่มต้น `/slack/events`) เพื่อไม่ให้การลงทะเบียนชนกัน - + ```bash openclaw gateway @@ -140,9 +140,9 @@ openclaw gateway -## การปรับแต่งการส่งผ่าน Socket Mode +## การปรับแต่งการส่งข้อมูลของ Socket Mode -OpenClaw ตั้งค่าระยะหมดเวลารอ pong ของไคลเอนต์ Slack SDK เป็น 15 วินาทีโดยค่าเริ่มต้นสำหรับ Socket Mode ให้แทนที่การตั้งค่าการส่งผ่านเฉพาะเมื่อคุณต้องปรับแต่งตามเวิร์กสเปซหรือโฮสต์เท่านั้น: +OpenClaw ตั้งค่า pong timeout ของไคลเอนต์ Slack SDK เป็น 15 วินาทีโดยค่าเริ่มต้นสำหรับ Socket Mode ให้แทนที่การตั้งค่าการส่งข้อมูลเฉพาะเมื่อคุณต้องปรับแต่งตาม workspace หรือโฮสต์เท่านั้น: ```json5 { @@ -159,13 +159,13 @@ OpenClaw ตั้งค่าระยะหมดเวลารอ pong ข } ``` -ใช้ตัวเลือกนี้เฉพาะกับเวิร์กสเปซ Socket Mode ที่บันทึก timeout ของ Slack websocket pong/server-ping หรือทำงานบนโฮสต์ที่ทราบว่ามีภาวะ event-loop starvation `clientPingTimeout` คือเวลารอ pong หลังจาก SDK ส่ง client ping; `serverPingTimeout` คือเวลารอ ping จากเซิร์ฟเวอร์ Slack ข้อความและอีเวนต์ของแอปยังคงเป็นสถานะแอปพลิเคชัน ไม่ใช่สัญญาณความพร้อมใช้งานของการส่งผ่าน +ใช้ตัวเลือกนี้เฉพาะกับ workspace ของ Socket Mode ที่บันทึก Slack websocket pong/server-ping timeout หรือทำงานบนโฮสต์ที่มีปัญหา event-loop starvation ที่ทราบอยู่แล้ว `clientPingTimeout` คือเวลารอ pong หลังจาก SDK ส่ง client ping ส่วน `serverPingTimeout` คือเวลารอ ping จากเซิร์ฟเวอร์ Slack ข้อความและเหตุการณ์ของแอปยังคงเป็นสถานะแอปพลิเคชัน ไม่ใช่สัญญาณความพร้อมของการส่งข้อมูล -## รายการตรวจสอบแมนิเฟสต์และขอบเขต +## รายการตรวจสอบ manifest และ scope -แมนิเฟสต์แอป Slack พื้นฐานเหมือนกันสำหรับ Socket Mode และ HTTP Request URLs มีเพียงบล็อก `settings` (และ `url` ของ slash command) ที่แตกต่างกัน +Slack app manifest พื้นฐานเหมือนกันสำหรับ Socket Mode และ HTTP Request URLs มีเฉพาะบล็อก `settings` (และ `url` ของคำสั่ง slash) ที่ต่างกัน -แมนิเฟสต์พื้นฐาน (ค่าเริ่มต้น Socket Mode): +manifest พื้นฐาน (ค่าเริ่มต้น Socket Mode): ```json { @@ -240,7 +240,7 @@ OpenClaw ตั้งค่าระยะหมดเวลารอ pong ข } ``` -สำหรับ **โหมด HTTP Request URLs** ให้แทนที่ `settings` ด้วยตัวแปร HTTP และเพิ่ม `url` ให้แต่ละ slash command ต้องมี URL สาธารณะ: +สำหรับ **โหมด HTTP Request URLs** ให้แทนที่ `settings` ด้วยตัวแปร HTTP และเพิ่ม `url` ในแต่ละคำสั่ง slash ต้องมี URL สาธารณะ: ```json { @@ -282,24 +282,24 @@ OpenClaw ตั้งค่าระยะหมดเวลารอ pong ข } ``` -### การตั้งค่าแมนิเฟสต์เพิ่มเติม +### การตั้งค่า manifest เพิ่มเติม แสดงฟีเจอร์ต่าง ๆ ที่ขยายค่าเริ่มต้นด้านบน -แมนิเฟสต์เริ่มต้นเปิดใช้แท็บ **Home** ของ Slack App Home และสมัครรับ `app_home_opened` เมื่อสมาชิกเวิร์กสเปซเปิดแท็บ Home, OpenClaw จะเผยแพร่มุมมอง Home เริ่มต้นที่ปลอดภัยด้วย `views.publish`; ไม่มีเพย์โหลดการสนทนาหรือการกำหนดค่าส่วนตัวรวมอยู่ แท็บ **Messages** ยังคงเปิดใช้งานสำหรับ Slack DM +manifest เริ่มต้นเปิดใช้แท็บ **Home** ของ Slack App Home และสมัครรับ `app_home_opened` เมื่อสมาชิก workspace เปิดแท็บ Home, OpenClaw จะเผยแพร่มุมมอง Home เริ่มต้นที่ปลอดภัยด้วย `views.publish` โดยไม่รวม payload การสนทนาหรือการกำหนดค่าส่วนตัว แท็บ **Messages** ยังคงเปิดใช้สำหรับ Slack DM - + - สามารถใช้ [slash command แบบเนทีฟ](#commands-and-slash-behavior) หลายรายการแทนคำสั่งที่กำหนดค่าไว้รายการเดียวได้ โดยมีรายละเอียดดังนี้: + สามารถใช้ [คำสั่ง slash แบบเนทีฟ](#commands-and-slash-behavior) หลายคำสั่งแทนคำสั่งเดียวที่กำหนดค่าไว้พร้อมรายละเอียดปลีกย่อยได้: - ใช้ `/agentstatus` แทน `/status` เพราะคำสั่ง `/status` ถูกสงวนไว้ - - ทำให้มี slash command ใช้งานได้พร้อมกันไม่เกิน 25 รายการ + - สามารถเปิดให้ใช้คำสั่ง slash ได้พร้อมกันไม่เกิน 25 คำสั่ง - แทนที่ส่วน `features.slash_commands` เดิมของคุณด้วยชุดย่อยของ [คำสั่งที่มีให้ใช้](/th/tools/slash-commands#command-list): + แทนที่ส่วน `features.slash_commands` ที่มีอยู่ด้วยชุดย่อยของ [คำสั่งที่มีให้ใช้](/th/tools/slash-commands#command-list): - + ```json { @@ -423,7 +423,7 @@ OpenClaw ตั้งค่าระยะหมดเวลารอ pong ข - ใช้รายการ `slash_commands` เดียวกับ Socket Mode ด้านบน และเพิ่ม `"url": "https://gateway-host.example.com/slack/events"` ให้ทุกรายการ ตัวอย่าง: + ใช้รายการ `slash_commands` เดียวกับ Socket Mode ด้านบน และเพิ่ม `"url": "https://gateway-host.example.com/slack/events"` ในทุกรายการ ตัวอย่าง: ```json { @@ -449,14 +449,14 @@ OpenClaw ตั้งค่าระยะหมดเวลารอ pong ข - - เพิ่มขอบเขตบอท `chat:write.customize` หากคุณต้องการให้ข้อความขาออกใช้ตัวตนของเอเจนต์ที่ใช้งานอยู่ (ชื่อผู้ใช้และไอคอนแบบกำหนดเอง) แทนตัวตนเริ่มต้นของแอป Slack + + เพิ่มขอบเขตบอต `chat:write.customize` หากคุณต้องการให้ข้อความขาออกใช้อัตลักษณ์ของเอเจนต์ที่ใช้งานอยู่ (ชื่อผู้ใช้และไอคอนแบบกำหนดเอง) แทนอัตลักษณ์เริ่มต้นของแอป Slack - หากคุณใช้ไอคอนอีโมจิ Slack คาดหวังไวยากรณ์ `:emoji_name:` + หากคุณใช้ไอคอนอีโมจิ Slack คาดหวังไวยากรณ์แบบ `:emoji_name:` - - หากคุณกำหนดค่า `channels.slack.userToken` ขอบเขตการอ่านทั่วไปคือ: + + หากคุณกำหนดค่า `channels.slack.userToken` ขอบเขตการอ่านโดยทั่วไปคือ: - `channels:history`, `groups:history`, `im:history`, `mpim:history` - `channels:read`, `groups:read`, `im:read`, `mpim:read` @@ -464,41 +464,41 @@ OpenClaw ตั้งค่าระยะหมดเวลารอ pong ข - `reactions:read` - `pins:read` - `emoji:read` - - `search:read` (หากคุณพึ่งพาการอ่านจากการค้นหาของ Slack) + - `search:read` (หากคุณพึ่งพาการอ่านการค้นหาของ Slack) ## โมเดลโทเค็น -- ต้องมี `botToken` + `appToken` สำหรับ Socket Mode -- โหมด HTTP ต้องมี `botToken` + `signingSecret` -- `botToken`, `appToken`, `signingSecret` และ `userToken` รับสตริงข้อความล้วน +- จำเป็นต้องมี `botToken` + `appToken` สำหรับ Socket Mode +- โหมด HTTP ต้องใช้ `botToken` + `signingSecret` +- `botToken`, `appToken`, `signingSecret` และ `userToken` รับสตริงข้อความธรรมดา หรือออบเจ็กต์ SecretRef -- โทเค็นในค่ากำหนดจะแทนที่ env fallback -- env fallback `SLACK_BOT_TOKEN` / `SLACK_APP_TOKEN` ใช้กับบัญชีเริ่มต้นเท่านั้น -- `userToken` (`xoxp-...`) กำหนดค่าได้ผ่าน config เท่านั้น (ไม่มี env fallback) และค่าเริ่มต้นเป็นพฤติกรรมแบบอ่านอย่างเดียว (`userTokenReadOnly: true`) +- โทเค็นในคอนฟิกจะแทนที่ env fallback +- env fallback ของ `SLACK_BOT_TOKEN` / `SLACK_APP_TOKEN` ใช้กับบัญชีเริ่มต้นเท่านั้น +- `userToken` (`xoxp-...`) เป็นแบบคอนฟิกเท่านั้น (ไม่มี env fallback) และมีค่าเริ่มต้นเป็นพฤติกรรมอ่านอย่างเดียว (`userTokenReadOnly: true`) พฤติกรรมสแนปช็อตสถานะ: - การตรวจสอบบัญชี Slack ติดตามฟิลด์ `*Source` และ `*Status` - ต่อข้อมูลรับรอง (`botToken`, `appToken`, `signingSecret`, `userToken`) + ต่อข้อมูลประจำตัว (`botToken`, `appToken`, `signingSecret`, `userToken`) - สถานะคือ `available`, `configured_unavailable` หรือ `missing` - `configured_unavailable` หมายความว่าบัญชีถูกกำหนดค่าผ่าน SecretRef - หรือแหล่งข้อมูลลับแบบไม่ฝังในบรรทัดแบบอื่น แต่เส้นทางคำสั่ง/รันไทม์ปัจจุบัน - ไม่สามารถ resolve ค่าจริงได้ -- ในโหมด HTTP จะรวม `signingSecretStatus`; ใน Socket Mode + หรือแหล่งความลับแบบไม่ฝังในบรรทัดอื่น แต่เส้นทางคำสั่ง/รันไทม์ปัจจุบัน + ไม่สามารถแก้ค่าแท้จริงได้ +- ในโหมด HTTP จะรวม `signingSecretStatus` ไว้ด้วย; ใน Socket Mode คู่ที่จำเป็นคือ `botTokenStatus` + `appTokenStatus` -สำหรับ actions/การอ่าน directory สามารถเลือกใช้โทเค็นผู้ใช้ก่อนเมื่อกำหนดค่าไว้ สำหรับการเขียน โทเค็นบอทยังคงเป็นตัวเลือกหลัก; การเขียนด้วยโทเค็นผู้ใช้จะอนุญาตเฉพาะเมื่อ `userTokenReadOnly: false` และไม่มีโทเค็นบอทให้ใช้ +สำหรับการอ่านแอ็กชัน/ไดเรกทอรี สามารถเลือกใช้โทเค็นผู้ใช้ก่อนเมื่อกำหนดค่าไว้ สำหรับการเขียน โทเค็นบอตยังคงเป็นตัวเลือกหลัก; การเขียนด้วยโทเค็นผู้ใช้จะอนุญาตเฉพาะเมื่อ `userTokenReadOnly: false` และโทเค็นบอตไม่พร้อมใช้งาน -## Actions และ gates +## แอ็กชันและเกต -Slack actions ถูกควบคุมโดย `channels.slack.actions.*` +แอ็กชัน Slack ควบคุมโดย `channels.slack.actions.*` -กลุ่ม action ที่มีในเครื่องมือ Slack ปัจจุบัน: +กลุ่มแอ็กชันที่พร้อมใช้งานในเครื่องมือ Slack ปัจจุบัน: | กลุ่ม | ค่าเริ่มต้น | | ---------- | ------- | @@ -508,12 +508,12 @@ Slack actions ถูกควบคุมโดย `channels.slack.actions.*` | memberInfo | เปิดใช้งาน | | emojiList | เปิดใช้งาน | -action ข้อความ Slack ปัจจุบันประกอบด้วย `send`, `upload-file`, `download-file`, `read`, `edit`, `delete`, `pin`, `unpin`, `list-pins`, `member-info` และ `emoji-list` `download-file` รับ ID ไฟล์ Slack ที่แสดงใน placeholder ไฟล์ขาเข้า และส่งคืนตัวอย่างภาพสำหรับรูปภาพหรือ metadata ของไฟล์ภายในเครื่องสำหรับไฟล์ชนิดอื่น +แอ็กชันข้อความ Slack ปัจจุบันประกอบด้วย `send`, `upload-file`, `download-file`, `read`, `edit`, `delete`, `pin`, `unpin`, `list-pins`, `member-info` และ `emoji-list` `download-file` รับ ID ไฟล์ Slack ที่แสดงในตัวแทนที่ไฟล์ขาเข้า และคืนค่าตัวอย่างรูปภาพสำหรับรูปภาพ หรือเมตาดาต้าไฟล์ในเครื่องสำหรับไฟล์ประเภทอื่น ## การควบคุมการเข้าถึงและการกำหนดเส้นทาง - + `channels.slack.dmPolicy` ควบคุมการเข้าถึง DM `channels.slack.allowFrom` คือ allowlist ของ DM ตามมาตรฐาน - `pairing` (ค่าเริ่มต้น) @@ -526,40 +526,40 @@ action ข้อความ Slack ปัจจุบันประกอบด - `dm.enabled` (ค่าเริ่มต้น true) - `channels.slack.allowFrom` - `dm.allowFrom` (เดิม) - - `dm.groupEnabled` (DM กลุ่มมีค่าเริ่มต้นเป็น false) - - `dm.groupChannels` (allowlist MPIM แบบไม่บังคับ) + - `dm.groupEnabled` (DM แบบกลุ่มมีค่าเริ่มต้น false) + - `dm.groupChannels` (allowlist MPIM เพิ่มเติม) - ลำดับความสำคัญแบบหลายบัญชี: + ลำดับความสำคัญของหลายบัญชี: - `channels.slack.accounts.default.allowFrom` ใช้กับบัญชี `default` เท่านั้น - บัญชีที่มีชื่อจะสืบทอด `channels.slack.allowFrom` เมื่อไม่ได้ตั้งค่า `allowFrom` ของตัวเอง - บัญชีที่มีชื่อจะไม่สืบทอด `channels.slack.accounts.default.allowFrom` - `channels.slack.dm.policy` และ `channels.slack.dm.allowFrom` แบบเดิมยังอ่านได้เพื่อความเข้ากันได้ `openclaw doctor --fix` จะย้ายค่าเหล่านี้ไปเป็น `dmPolicy` และ `allowFrom` เมื่อทำได้โดยไม่เปลี่ยนการเข้าถึง + ยังคงอ่าน `channels.slack.dm.policy` และ `channels.slack.dm.allowFrom` เดิมเพื่อความเข้ากันได้ `openclaw doctor --fix` จะย้ายค่าเหล่านี้ไปยัง `dmPolicy` และ `allowFrom` เมื่อทำได้โดยไม่เปลี่ยนการเข้าถึง การจับคู่ใน DM ใช้ `openclaw pairing approve slack ` - + `channels.slack.groupPolicy` ควบคุมการจัดการช่อง: - `open` - `allowlist` - `disabled` - allowlist ของช่องอยู่ใต้ `channels.slack.channels` และ **ต้องใช้ ID ช่อง Slack ที่เสถียร** (เช่น `C12345678`) เป็นคีย์ config + allowlist ของช่องอยู่ภายใต้ `channels.slack.channels` และ**ต้องใช้ ID ช่อง Slack ที่เสถียร** (เช่น `C12345678`) เป็นคีย์คอนฟิก - หมายเหตุรันไทม์: หากไม่มี `channels.slack` เลย (การตั้งค่าแบบ env เท่านั้น) รันไทม์จะ fallback ไปที่ `groupPolicy="allowlist"` และบันทึกคำเตือน (แม้ว่าจะตั้งค่า `channels.defaults.groupPolicy` ไว้ก็ตาม) + หมายเหตุรันไทม์: หาก `channels.slack` หายไปทั้งหมด (การตั้งค่าแบบ env-only) รันไทม์จะ fallback ไปเป็น `groupPolicy="allowlist"` และบันทึกคำเตือน (แม้จะตั้งค่า `channels.defaults.groupPolicy` ไว้ก็ตาม) - การ resolve ชื่อ/ID: + การแก้ชื่อ/ID: - - รายการ allowlist ของช่องและรายการ allowlist ของ DM จะถูก resolve ตอนเริ่มทำงานเมื่อการเข้าถึงโทเค็นอนุญาต - - รายการชื่อช่องที่ resolve ไม่ได้จะถูกเก็บไว้ตามที่กำหนดค่า แต่จะถูกละเว้นสำหรับการกำหนดเส้นทางโดยค่าเริ่มต้น - - การอนุญาตขาเข้าและการกำหนดเส้นทางช่องจะใช้ ID ก่อนโดยค่าเริ่มต้น; การจับคู่ชื่อผู้ใช้/slug โดยตรงต้องใช้ `channels.slack.dangerouslyAllowNameMatching: true` + - รายการ allowlist ของช่องและรายการ allowlist ของ DM จะถูกแก้ตอนเริ่มต้นเมื่อการเข้าถึงโทเค็นอนุญาต + - รายการชื่อช่องที่แก้ไม่ได้จะคงไว้ตามที่กำหนดค่า แต่จะถูกละเว้นสำหรับการกำหนดเส้นทางโดยค่าเริ่มต้น + - การอนุญาตขาเข้าและการกำหนดเส้นทางช่องจะใช้ ID เป็นหลักโดยค่าเริ่มต้น; การจับคู่ชื่อผู้ใช้/slug โดยตรงต้องใช้ `channels.slack.dangerouslyAllowNameMatching: true` - คีย์ตามชื่อ (`#channel-name` หรือ `channel-name`) **จะไม่** ตรงกันภายใต้ `groupPolicy: "allowlist"` การค้นหาช่องใช้ ID ก่อนโดยค่าเริ่มต้น ดังนั้นคีย์ตามชื่อจะไม่สามารถกำหนดเส้นทางสำเร็จได้เลย และข้อความทั้งหมดในช่องนั้นจะถูกบล็อกอย่างเงียบ ๆ ซึ่งต่างจาก `groupPolicy: "open"` ที่ไม่ต้องใช้คีย์ช่องสำหรับการกำหนดเส้นทาง และคีย์ตามชื่อดูเหมือนจะใช้งานได้ + คีย์ตามชื่อ (`#channel-name` หรือ `channel-name`) จะ**ไม่**จับคู่ภายใต้ `groupPolicy: "allowlist"` การค้นหาช่องใช้ ID เป็นหลักโดยค่าเริ่มต้น ดังนั้นคีย์ตามชื่อจะไม่มีทางกำหนดเส้นทางสำเร็จ และข้อความทั้งหมดในช่องนั้นจะถูกบล็อกอย่างเงียบ ๆ ซึ่งแตกต่างจาก `groupPolicy: "open"` ที่ไม่จำเป็นต้องใช้คีย์ช่องสำหรับการกำหนดเส้นทาง และคีย์ตามชื่อดูเหมือนจะใช้งานได้ ใช้ ID ช่อง Slack เป็นคีย์เสมอ วิธีค้นหา: คลิกขวาที่ช่องใน Slack → **Copy link** — ID (`C...`) จะปรากฏที่ท้าย URL @@ -597,16 +597,16 @@ action ข้อความ Slack ปัจจุบันประกอบด - ข้อความในช่องถูกกั้นด้วยการกล่าวถึงโดยค่าเริ่มต้น + ข้อความในช่องทางถูกควบคุมด้วยการกล่าวถึงโดยค่าเริ่มต้น แหล่งที่มาของการกล่าวถึง: - การกล่าวถึงแอปอย่างชัดเจน (`<@botId>`) - - การกล่าวถึงกลุ่มผู้ใช้ Slack (``) เมื่อผู้ใช้บอทเป็นสมาชิกของกลุ่มผู้ใช้นั้น; ต้องมี `usergroups:read` - - รูปแบบ regex สำหรับการกล่าวถึง (`agents.list[].groupChat.mentionPatterns`, fallback `messages.groupChat.mentionPatterns`) - - พฤติกรรม thread แบบตอบกลับถึงบอทโดยนัย (ปิดใช้งานเมื่อ `thread.requireExplicitMention` เป็น `true`) + - การกล่าวถึงกลุ่มผู้ใช้ Slack (``) เมื่อผู้ใช้บอทเป็นสมาชิกของกลุ่มผู้ใช้นั้น ต้องใช้ `usergroups:read` + - รูปแบบ regex สำหรับการกล่าวถึง (`agents.list[].groupChat.mentionPatterns`, สำรองเป็น `messages.groupChat.mentionPatterns`) + - พฤติกรรมเธรดตอบกลับถึงบอทโดยนัย (ปิดใช้งานเมื่อ `thread.requireExplicitMention` เป็น `true`) - การควบคุมรายช่อง (`channels.slack.channels.`; ชื่อใช้ได้เฉพาะผ่านการ resolve ตอนเริ่มทำงานหรือ `dangerouslyAllowNameMatching`): + การควบคุมรายช่องทาง (`channels.slack.channels.`; ใช้ชื่อได้เฉพาะผ่านการแก้ค่าเมื่อเริ่มต้นหรือ `dangerouslyAllowNameMatching`): - `requireMention` - `users` (allowlist) @@ -614,55 +614,55 @@ action ข้อความ Slack ปัจจุบันประกอบด - `skills` - `systemPrompt` - `tools`, `toolsBySender` - - รูปแบบคีย์ `toolsBySender`: `id:`, `e164:`, `username:`, `name:` หรือ wildcard `"*"` - (คีย์เดิมที่ไม่มี prefix ยัง map ไปที่ `id:` เท่านั้น) + - รูปแบบคีย์ของ `toolsBySender`: `id:`, `e164:`, `username:`, `name:`, หรือ wildcard `"*"` + (คีย์แบบเดิมที่ไม่มีคำนำหน้ายังคงแมปไปยัง `id:` เท่านั้น) - `allowBots` เป็นแบบระมัดระวังสำหรับช่องและช่องส่วนตัว: ข้อความในห้องที่เขียนโดยบอทจะถูกรับเฉพาะเมื่อบอทผู้ส่งอยู่ใน allowlist `users` ของห้องนั้นอย่างชัดเจน หรือเมื่อมี ID เจ้าของ Slack ที่ชัดเจนอย่างน้อยหนึ่งรายการจาก `channels.slack.allowFrom` เป็นสมาชิกห้องอยู่ในปัจจุบัน wildcard และรายการเจ้าของแบบชื่อที่แสดงไม่ถือว่าตอบสนองเงื่อนไขการมีอยู่ของเจ้าของ การมีอยู่ของเจ้าของใช้ Slack `conversations.members`; ตรวจสอบให้แน่ใจว่าแอปมีขอบเขตการอ่านที่ตรงกับชนิดห้อง (`channels:read` สำหรับช่องสาธารณะ, `groups:read` สำหรับช่องส่วนตัว) หากการค้นหาสมาชิกล้มเหลว OpenClaw จะทิ้งข้อความในห้องที่เขียนโดยบอท + `allowBots` มีความระมัดระวังสำหรับช่องทางและช่องทางส่วนตัว: ข้อความในห้องที่เขียนโดยบอทจะถูกรับเฉพาะเมื่อบอทผู้ส่งถูกระบุไว้อย่างชัดเจนใน allowlist `users` ของห้องนั้น หรือเมื่อมี ID เจ้าของ Slack ที่ชัดเจนอย่างน้อยหนึ่งรายการจาก `channels.slack.allowFrom` เป็นสมาชิกห้องอยู่ในขณะนั้น wildcard และรายการเจ้าของที่เป็นชื่อที่แสดงไม่ถือว่าเป็นการมีอยู่ของเจ้าของ การมีอยู่ของเจ้าของใช้ Slack `conversations.members`; ตรวจสอบให้แน่ใจว่าแอปมี scope อ่านที่ตรงกับประเภทห้อง (`channels:read` สำหรับช่องทางสาธารณะ, `groups:read` สำหรับช่องทางส่วนตัว) หากการค้นหาสมาชิกล้มเหลว OpenClaw จะทิ้งข้อความในห้องที่เขียนโดยบอท -## Threading, sessions และแท็กตอบกลับ +## เธรด เซสชัน และแท็กตอบกลับ -- DM กำหนดเส้นทางเป็น `direct`; ช่องเป็น `channel`; MPIM เป็น `group` -- การผูกเส้นทาง Slack รับ ID peer แบบดิบ รวมถึงรูปแบบเป้าหมาย Slack เช่น `channel:C12345678`, `user:U12345678` และ `<@U12345678>` -- ด้วยค่าเริ่มต้น `session.dmScope=main` DM ของ Slack จะถูกรวมไปที่ session หลักของเอเจนต์ -- session ช่อง: `agent::slack:channel:` -- การตอบกลับใน thread สามารถสร้าง suffix ของ session thread (`:thread:`) ได้เมื่อเกี่ยวข้อง +- DM กำหนดเส้นทางเป็น `direct`; ช่องทางเป็น `channel`; MPIM เป็น `group` +- การผูกเส้นทางของ Slack รับ ID เพียร์ดิบ รวมถึงรูปแบบเป้าหมาย Slack เช่น `channel:C12345678`, `user:U12345678`, และ `<@U12345678>` +- ด้วยค่าเริ่มต้น `session.dmScope=main` DM ของ Slack จะยุบรวมเข้าเซสชันหลักของเอเจนต์ +- เซสชันช่องทาง: `agent::slack:channel:` +- การตอบกลับในเธรดสามารถสร้างส่วนท้ายเซสชันของเธรด (`:thread:`) เมื่อใช้ได้ - ค่าเริ่มต้นของ `channels.slack.thread.historyScope` คือ `thread`; ค่าเริ่มต้นของ `thread.inheritParent` คือ `false` -- `channels.slack.thread.initialHistoryLimit` ควบคุมจำนวนข้อความ thread ที่มีอยู่ซึ่งจะถูกดึงเมื่อ session thread ใหม่เริ่มต้น (ค่าเริ่มต้น `20`; ตั้ง `0` เพื่อปิดใช้งาน) -- `channels.slack.thread.requireExplicitMention` (ค่าเริ่มต้น `false`): เมื่อเป็น `true` จะระงับการกล่าวถึง thread โดยนัย เพื่อให้บอทตอบกลับเฉพาะการกล่าวถึง `@bot` อย่างชัดเจนภายใน thread แม้ว่าบอทจะเคยเข้าร่วมใน thread แล้วก็ตาม หากไม่มีค่านี้ การตอบกลับใน thread ที่บอทเคยเข้าร่วมจะข้าม gating ของ `requireMention` +- `channels.slack.thread.initialHistoryLimit` ควบคุมจำนวนข้อความเธรดที่มีอยู่ซึ่งจะถูกดึงเมื่อเซสชันเธรดใหม่เริ่มต้น (ค่าเริ่มต้น `20`; ตั้งเป็น `0` เพื่อปิดใช้งาน) +- `channels.slack.thread.requireExplicitMention` (ค่าเริ่มต้น `false`): เมื่อเป็น `true` จะระงับการกล่าวถึงเธรดโดยนัย เพื่อให้บอทตอบเฉพาะการกล่าวถึง `@bot` อย่างชัดเจนภายในเธรด แม้ว่าบอทจะเคยเข้าร่วมเธรดนั้นแล้วก็ตาม หากไม่มีค่านี้ การตอบกลับในเธรดที่บอทเคยเข้าร่วมจะข้ามการควบคุม `requireMention` -การควบคุม reply threading: +การควบคุมเธรดการตอบกลับ: - `channels.slack.replyToMode`: `off|first|all|batched` (ค่าเริ่มต้น `off`) -- `channels.slack.replyToModeByChatType`: ต่อ `direct|group|channel` -- fallback เดิมสำหรับแชทโดยตรง: `channels.slack.dm.replyToMode` +- `channels.slack.replyToModeByChatType`: แยกตาม `direct|group|channel` +- ค่าสำรองเดิมสำหรับแชทโดยตรง: `channels.slack.dm.replyToMode` -รองรับแท็กตอบกลับแบบแมนนวล: +รองรับแท็กตอบกลับแบบกำหนดเอง: - `[[reply_to_current]]` - `[[reply_to:]]` -`replyToMode="off"` ปิดใช้งาน reply threading **ทั้งหมด** ใน Slack รวมถึงแท็ก `[[reply_to_*]]` ที่ระบุอย่างชัดเจน ซึ่งต่างจาก Telegram ที่แท็กชัดเจนยังคงทำงานในโหมด `"off"` thread ของ Slack ซ่อนข้อความจากช่อง ขณะที่การตอบกลับของ Telegram ยังคงมองเห็นแบบ inline +`replyToMode="off"` ปิดใช้งานเธรดการตอบกลับ **ทั้งหมด** ใน Slack รวมถึงแท็ก `[[reply_to_*]]` ที่ชัดเจน ซึ่งต่างจาก Telegram ที่ยังคงใช้แท็กที่ชัดเจนในโหมด `"off"` อยู่ เธรดของ Slack ซ่อนข้อความจากช่องทาง ขณะที่การตอบกลับของ Telegram ยังคงมองเห็นแบบอินไลน์ -## รีแอ็กชันตอบรับ +## รีแอ็กชันรับทราบ -`ackReaction` ส่งอีโมจิยืนยันขณะที่ OpenClaw กำลังประมวลผลข้อความขาเข้า +`ackReaction` ส่งอีโมจิรับทราบขณะที่ OpenClaw กำลังประมวลผลข้อความขาเข้า -ลำดับการ resolve: +ลำดับการแก้ค่า: - `channels.slack.accounts..ackReaction` - `channels.slack.ackReaction` - `messages.ackReaction` -- fallback อีโมจิตัวตนของเอเจนต์ (`agents.list[].identity.emoji`, มิฉะนั้น "👀") +- อีโมจิสำรองจากตัวตนของเอเจนต์ (`agents.list[].identity.emoji`, มิฉะนั้นเป็น "👀") หมายเหตุ: - Slack คาดหวัง shortcode (เช่น `"eyes"`) -- ใช้ `""` เพื่อปิดใช้งานรีแอ็กชันสำหรับบัญชี Slack หรือทั้งระบบ +- ใช้ `""` เพื่อปิดใช้งานรีแอ็กชันสำหรับบัญชี Slack หรือทั่วทั้งระบบ ## การสตรีมข้อความ @@ -670,20 +670,39 @@ action ข้อความ Slack ปัจจุบันประกอบด - `off`: ปิดใช้งานการสตรีมตัวอย่างสด - `partial` (ค่าเริ่มต้น): แทนที่ข้อความตัวอย่างด้วยผลลัพธ์บางส่วนล่าสุด -- `block`: ต่อท้ายการอัปเดตตัวอย่างแบบแบ่ง chunk -- `progress`: แสดงข้อความสถานะความคืบหน้าขณะสร้าง จากนั้นส่งข้อความสุดท้าย -- `streaming.preview.toolProgress`: เมื่อตัวอย่างฉบับร่างทำงานอยู่ ให้กำหนดเส้นทางการอัปเดตเครื่องมือ/ความคืบหน้าเข้าไปในข้อความตัวอย่างที่แก้ไขข้อความเดียวกัน (ค่าเริ่มต้น: `true`) ตั้งเป็น `false` เพื่อคงข้อความเครื่องมือ/ความคืบหน้าแยกกัน +- `block`: ต่อท้ายการอัปเดตตัวอย่างเป็นชิ้น ๆ +- `progress`: แสดงข้อความสถานะความคืบหน้าระหว่างสร้าง แล้วจึงส่งข้อความสุดท้าย +- `streaming.preview.toolProgress`: เมื่อตัวอย่างฉบับร่างทำงาน ให้กำหนดเส้นทางการอัปเดตเครื่องมือ/ความคืบหน้าเข้าไปยังข้อความตัวอย่างที่ถูกแก้ไขเดียวกัน (ค่าเริ่มต้น: `true`) ตั้งเป็น `false` เพื่อแยกข้อความเครื่องมือ/ความคืบหน้าออกต่างหาก +- `streaming.preview.commandText` / `streaming.progress.commandText`: ตั้งเป็น `status` เพื่อคงบรรทัดความคืบหน้าของเครื่องมือแบบกะทัดรัด พร้อมซ่อนข้อความคำสั่ง/การดำเนินการดิบ (ค่าเริ่มต้น: `raw`) -`channels.slack.streaming.nativeTransport` ควบคุมการสตรีมข้อความ native ของ Slack เมื่อ `channels.slack.streaming.mode` เป็น `partial` (ค่าเริ่มต้น: `true`) +ซ่อนข้อความคำสั่ง/การดำเนินการดิบ พร้อมคงบรรทัดความคืบหน้าแบบกะทัดรัด: -- ต้องมี thread ตอบกลับเพื่อให้การสตรีมข้อความ native และสถานะ thread assistant ของ Slack ปรากฏ การเลือก thread ยังคงทำตาม `replyToMode` -- ช่อง, แชทกลุ่ม และราก DM ระดับบนสุดยังสามารถใช้ตัวอย่างฉบับร่างปกติได้เมื่อ native streaming ไม่พร้อมใช้งานหรือไม่มี thread ตอบกลับ -- DM ของ Slack ระดับบนสุดจะอยู่นอก thread โดยค่าเริ่มต้น ดังนั้นจึงไม่แสดงตัวอย่าง native stream/status แบบ thread-style ของ Slack; OpenClaw จะโพสต์และแก้ไขตัวอย่างฉบับร่างใน DM แทน -- payload สื่อและที่ไม่ใช่ข้อความจะ fallback ไปยังการส่งมอบปกติ -- ผลสุดท้ายของสื่อ/ข้อผิดพลาดจะยกเลิกการแก้ไขตัวอย่างที่ค้างอยู่; ผลสุดท้ายแบบข้อความ/บล็อกที่เข้าเกณฑ์จะ flush เฉพาะเมื่อสามารถแก้ไขตัวอย่างในตำแหน่งเดิมได้ -- หากการสตรีมล้มเหลวระหว่างตอบกลับ OpenClaw จะ fallback ไปยังการส่งมอบปกติสำหรับ payload ที่เหลือ +```json +{ + "channels": { + "slack": { + "streaming": { + "mode": "progress", + "progress": { + "toolProgress": true, + "commandText": "status" + } + } + } + } +} +``` -ใช้ตัวอย่างฉบับร่างแทนการสตรีมข้อความ native ของ Slack: +`channels.slack.streaming.nativeTransport` ควบคุมการสตรีมข้อความแบบเนทีฟของ Slack เมื่อ `channels.slack.streaming.mode` เป็น `partial` (ค่าเริ่มต้น: `true`) + +- ต้องมีเธรดตอบกลับสำหรับการสตรีมข้อความแบบเนทีฟและเพื่อให้สถานะเธรดผู้ช่วยของ Slack ปรากฏ การเลือกเธรดยังคงเป็นไปตาม `replyToMode` +- รากของช่องทาง แชทกลุ่ม และ DM ระดับบนยังคงใช้ตัวอย่างฉบับร่างปกติได้เมื่อการสตรีมแบบเนทีฟใช้ไม่ได้หรือไม่มีเธรดตอบกลับ +- DM ระดับบนของ Slack ยังคงอยู่นอกเธรดโดยค่าเริ่มต้น ดังนั้นจึงไม่แสดงตัวอย่างสตรีม/สถานะแบบเนทีฟสไตล์เธรดของ Slack; OpenClaw จะโพสต์และแก้ไขตัวอย่างฉบับร่างใน DM แทน +- สื่อและ payload ที่ไม่ใช่ข้อความจะย้อนกลับไปใช้การส่งตามปกติ +- ผลลัพธ์สุดท้ายของสื่อ/ข้อผิดพลาดจะยกเลิกการแก้ไขตัวอย่างที่ค้างอยู่; ผลลัพธ์สุดท้ายของข้อความ/บล็อกที่เข้าเกณฑ์จะ flush เฉพาะเมื่อสามารถแก้ไขตัวอย่างเดิมได้ +- หากการสตรีมล้มเหลวระหว่างการตอบกลับ OpenClaw จะย้อนกลับไปใช้การส่งตามปกติสำหรับ payload ที่เหลือ + +ใช้ตัวอย่างฉบับร่างแทนการสตรีมข้อความแบบเนทีฟของ Slack: ```json5 { @@ -700,58 +719,58 @@ action ข้อความ Slack ปัจจุบันประกอบด คีย์เดิม: -- `channels.slack.streamMode` (`replace | status_final | append`) ถูกย้ายอัตโนมัติไปเป็น `channels.slack.streaming.mode` -- boolean `channels.slack.streaming` ถูกย้ายอัตโนมัติไปเป็น `channels.slack.streaming.mode` และ `channels.slack.streaming.nativeTransport` -- `channels.slack.nativeStreaming` เดิมถูกย้ายอัตโนมัติไปเป็น `channels.slack.streaming.nativeTransport` +- `channels.slack.streamMode` (`replace | status_final | append`) จะถูกย้ายโดยอัตโนมัติไปยัง `channels.slack.streaming.mode` +- boolean `channels.slack.streaming` จะถูกย้ายโดยอัตโนมัติไปยัง `channels.slack.streaming.mode` และ `channels.slack.streaming.nativeTransport` +- `channels.slack.nativeStreaming` แบบเดิมจะถูกย้ายโดยอัตโนมัติไปยัง `channels.slack.streaming.nativeTransport` -## fallback ของรีแอ็กชันการพิมพ์ +## ค่าสำรองรีแอ็กชันการพิมพ์ -`typingReaction` เพิ่มรีแอ็กชันชั่วคราวให้กับข้อความ Slack ขาเข้าขณะที่ OpenClaw กำลังประมวลผลการตอบกลับ จากนั้นลบออกเมื่อการรันเสร็จสิ้น สิ่งนี้มีประโยชน์มากที่สุดภายนอกการตอบกลับใน thread ซึ่งใช้ตัวบ่งชี้สถานะเริ่มต้น "is typing..." +`typingReaction` จะเพิ่มรีแอคชันชั่วคราวให้กับข้อความ Slack ขาเข้าขณะที่ OpenClaw กำลังประมวลผลคำตอบ แล้วลบออกเมื่อการรันเสร็จสิ้น วิธีนี้มีประโยชน์มากที่สุดนอกเหนือจากการตอบกลับในเธรด ซึ่งใช้ตัวบ่งชี้สถานะเริ่มต้นว่า "กำลังพิมพ์..." -ลำดับการ resolve: +ลำดับการแก้ไขค่า: - `channels.slack.accounts..typingReaction` - `channels.slack.typingReaction` หมายเหตุ: -- Slack คาดหวัง shortcode (เช่น `"hourglass_flowing_sand"`) -- reaction เป็นแบบ best-effort และจะพยายามล้างข้อมูลอัตโนมัติหลังจากเส้นทางการตอบกลับหรือความล้มเหลวเสร็จสิ้น +- Slack คาดหวัง shortcodes (ตัวอย่างเช่น `"hourglass_flowing_sand"`) +- รีแอคชันเป็นแบบพยายามอย่างดีที่สุด และจะพยายามล้างค่าโดยอัตโนมัติหลังจากเส้นทางการตอบกลับหรือความล้มเหลวเสร็จสมบูรณ์ -## สื่อ, การแบ่งชิ้นส่วน, และการส่งมอบ +## สื่อ การแบ่งชิ้น และการส่งมอบ - - ไฟล์แนบของ Slack จะถูกดาวน์โหลดจาก URL ส่วนตัวที่โฮสต์โดย Slack (โฟลว์คำขอที่ยืนยันตัวตนด้วย token) และเขียนลง media store เมื่อ fetch สำเร็จและขีดจำกัดขนาดอนุญาต placeholder ของไฟล์จะมี Slack `fileId` เพื่อให้ agent สามารถ fetch ไฟล์ต้นฉบับด้วย `download-file` + + ไฟล์แนบ Slack จะถูกดาวน์โหลดจาก URL ส่วนตัวที่ Slack โฮสต์ไว้ (โฟลว์คำขอที่ตรวจสอบสิทธิ์ด้วยโทเค็น) และเขียนลงในที่เก็บสื่อเมื่อดึงข้อมูลสำเร็จและข้อจำกัดขนาดอนุญาต ตัวแทนไฟล์มี `fileId` ของ Slack เพื่อให้เอเจนต์ดึงไฟล์ต้นฉบับด้วย `download-file` ได้ - การดาวน์โหลดใช้ timeout ทั้งแบบ idle และ total ที่มีขอบเขตจำกัด หากการดึงไฟล์ Slack ค้างหรือล้มเหลว OpenClaw จะประมวลผลข้อความต่อไปและ fallback ไปยัง placeholder ของไฟล์ + การดาวน์โหลดใช้ timeout แบบ idle และรวมที่มีขอบเขตจำกัด หากการดึงไฟล์ Slack ค้างหรือล้มเหลว OpenClaw จะประมวลผลข้อความต่อไปและถอยกลับไปใช้ตัวแทนไฟล์ - ค่าเริ่มต้นของขีดจำกัดขนาด inbound ระหว่าง runtime คือ `20MB` เว้นแต่จะถูก override ด้วย `channels.slack.mediaMaxMb` + ขีดจำกัดขนาดขาเข้าขณะรันมีค่าเริ่มต้นเป็น `20MB` เว้นแต่จะถูกแทนที่ด้วย `channels.slack.mediaMaxMb` - - - ชิ้นส่วนข้อความใช้ `channels.slack.textChunkLimit` (ค่าเริ่มต้น 4000) - - `channels.slack.chunkMode="newline"` เปิดใช้การแบ่งแบบย่อหน้าก่อน - - การส่งไฟล์ใช้ Slack upload APIs และสามารถรวมการตอบกลับใน thread (`thread_ts`) - - ขีดจำกัดสื่อ outbound จะทำตาม `channels.slack.mediaMaxMb` เมื่อกำหนดค่าไว้ มิฉะนั้นการส่งผ่าน channel จะใช้ค่าเริ่มต้นตามชนิด MIME จาก media pipeline + + - ชิ้นข้อความใช้ `channels.slack.textChunkLimit` (ค่าเริ่มต้น 4000) + - `channels.slack.chunkMode="newline"` เปิดใช้การแบ่งแบบยึดย่อหน้าเป็นหลัก + - การส่งไฟล์ใช้ API อัปโหลดของ Slack และสามารถรวมการตอบกลับในเธรด (`thread_ts`) ได้ + - ขีดจำกัดสื่อขาออกใช้ `channels.slack.mediaMaxMb` เมื่อกำหนดค่าไว้ มิฉะนั้นการส่งของช่องทางจะใช้ค่าเริ่มต้นตามชนิด MIME จากไปป์ไลน์สื่อ - - เป้าหมายแบบชัดเจนที่แนะนำ: + + เป้าหมายแบบระบุชัดเจนที่แนะนำ: - `user:` สำหรับ DM - - `channel:` สำหรับ channel + - `channel:` สำหรับช่องทาง - Slack DM ที่เป็นข้อความ/บล็อกเท่านั้นสามารถโพสต์ไปยัง user ID ได้โดยตรง ส่วนการอัปโหลดไฟล์และการส่งแบบ thread จะเปิด DM ผ่าน Slack conversation APIs ก่อน เพราะเส้นทางเหล่านั้นต้องใช้ conversation ID ที่เป็นรูปธรรม + DM ของ Slack ที่เป็นข้อความ/บล็อกอย่างเดียวสามารถโพสต์ไปยัง ID ผู้ใช้ได้โดยตรง ส่วนการอัปโหลดไฟล์และการส่งในเธรดจะเปิด DM ผ่าน API การสนทนาของ Slack ก่อน เพราะเส้นทางเหล่านั้นต้องใช้ ID การสนทนาที่เป็นรูปธรรม ## คำสั่งและพฤติกรรม slash -คำสั่ง slash จะปรากฏใน Slack เป็นคำสั่งเดียวที่กำหนดค่าไว้ หรือเป็นหลายคำสั่ง native กำหนดค่า `channels.slack.slashCommand` เพื่อเปลี่ยนค่าเริ่มต้นของคำสั่ง: +คำสั่ง slash ปรากฏใน Slack เป็นคำสั่งที่กำหนดค่าไว้คำสั่งเดียวหรือคำสั่ง native หลายคำสั่ง กำหนดค่า `channels.slack.slashCommand` เพื่อเปลี่ยนค่าเริ่มต้นของคำสั่ง: - `enabled: false` - `name: "openclaw"` @@ -762,32 +781,32 @@ action ข้อความ Slack ปัจจุบันประกอบด /openclaw /help ``` -คำสั่ง native ต้องใช้ [การตั้งค่า manifest เพิ่มเติม](#additional-manifest-settings) ในแอป Slack ของคุณ และเปิดใช้ด้วย `channels.slack.commands.native: true` หรือ `commands.native: true` ในการกำหนดค่าระดับ global แทน +คำสั่ง native ต้องใช้ [การตั้งค่า manifest เพิ่มเติม](#additional-manifest-settings) ในแอป Slack ของคุณ และเปิดใช้ด้วย `channels.slack.commands.native: true` หรือ `commands.native: true` ในการกำหนดค่าส่วนกลางแทน -- โหมดอัตโนมัติของคำสั่ง native จะ **ปิด** สำหรับ Slack ดังนั้น `commands.native: "auto"` จะไม่เปิดใช้คำสั่ง native ของ Slack +- โหมดอัตโนมัติของคำสั่ง native **ปิดอยู่** สำหรับ Slack ดังนั้น `commands.native: "auto"` จึงไม่เปิดใช้คำสั่ง native ของ Slack ```txt /help ``` -เมนู argument แบบ native ใช้กลยุทธ์การ render แบบ adaptive ที่แสดง modal ยืนยันก่อน dispatch ค่า option ที่เลือก: +เมนูอาร์กิวเมนต์ native ใช้กลยุทธ์การเรนเดอร์แบบปรับตามบริบท ซึ่งแสดงโมดัลยืนยันก่อน dispatch ค่าตัวเลือกที่เลือก: -- สูงสุด 5 options: บล็อกปุ่ม -- 6-100 options: เมนู static select -- มากกว่า 100 options: external select พร้อมการกรอง option แบบ async เมื่อมีตัวจัดการ interactivity options -- เกินขีดจำกัดของ Slack: ค่า option ที่เข้ารหัสจะ fallback ไปเป็นปุ่ม +- สูงสุด 5 ตัวเลือก: บล็อกปุ่ม +- 6-100 ตัวเลือก: เมนู static select +- มากกว่า 100 ตัวเลือก: external select พร้อมการกรองตัวเลือกแบบ async เมื่อมีตัวจัดการตัวเลือก interactivity +- เกินขีดจำกัดของ Slack: ค่าตัวเลือกที่เข้ารหัสจะถอยกลับไปใช้ปุ่ม ```txt /think ``` -session แบบ slash ใช้คีย์แยก เช่น `agent::slack:slash:` และยังคง route การรันคำสั่งไปยัง session การสนทนาเป้าหมายโดยใช้ `CommandTargetSessionKey` +เซสชัน slash ใช้คีย์แยกกัน เช่น `agent::slack:slash:` และยังคงกำหนดเส้นทางการดำเนินคำสั่งไปยังเซสชันการสนทนาเป้าหมายโดยใช้ `CommandTargetSessionKey` -## การตอบกลับแบบ interactive +## การตอบกลับแบบอินเทอร์แอคทีฟ -Slack สามารถ render คอนโทรลการตอบกลับแบบ interactive ที่ agent เขียนได้ แต่ฟีเจอร์นี้ถูกปิดไว้โดยค่าเริ่มต้น +Slack สามารถเรนเดอร์ตัวควบคุมการตอบกลับแบบอินเทอร์แอคทีฟที่เอเจนต์เขียนได้ แต่ฟีเจอร์นี้ถูกปิดไว้โดยค่าเริ่มต้น -เปิดใช้แบบ global: +เปิดใช้แบบทั่วทั้งระบบ: ```json5 { @@ -801,7 +820,7 @@ Slack สามารถ render คอนโทรลการตอบกลั } ``` -หรือเปิดใช้เฉพาะบัญชี Slack หนึ่งบัญชี: +หรือเปิดใช้เฉพาะบัญชี Slack บัญชีเดียว: ```json5 { @@ -819,44 +838,44 @@ Slack สามารถ render คอนโทรลการตอบกลั } ``` -เมื่อเปิดใช้แล้ว agent สามารถ emit directive การตอบกลับเฉพาะ Slack ได้: +เมื่อเปิดใช้ เอเจนต์สามารถปล่อย directive การตอบกลับเฉพาะ Slack ได้: - `[[slack_buttons: Approve:approve, Reject:reject]]` - `[[slack_select: Choose a target | Canary:canary, Production:production]]` -directive เหล่านี้จะ compile เป็น Slack Block Kit และ route การคลิกหรือการเลือกกลับผ่านเส้นทาง event interaction ของ Slack ที่มีอยู่ +Directive เหล่านี้คอมไพล์เป็น Slack Block Kit และกำหนดเส้นทางการคลิกหรือการเลือกกลับผ่านเส้นทางเหตุการณ์การโต้ตอบ Slack ที่มีอยู่ หมายเหตุ: -- นี่คือ UI เฉพาะ Slack channel อื่นจะไม่แปล directive ของ Slack Block Kit เป็นระบบปุ่มของตนเอง -- ค่า callback แบบ interactive เป็น opaque token ที่ OpenClaw สร้างขึ้น ไม่ใช่ค่าดิบที่ agent เขียน -- หากบล็อก interactive ที่สร้างขึ้นจะเกินขีดจำกัดของ Slack Block Kit, OpenClaw จะ fallback ไปยังข้อความตอบกลับเดิมแทนการส่ง payload blocks ที่ไม่ถูกต้อง +- นี่คือ UI เฉพาะ Slack ช่องทางอื่นจะไม่แปล directive ของ Slack Block Kit เป็นระบบปุ่มของตนเอง +- ค่าคอลแบ็กแบบอินเทอร์แอคทีฟเป็นโทเค็นทึบที่ OpenClaw สร้างขึ้น ไม่ใช่ค่าดิบที่เอเจนต์เขียน +- หากบล็อกอินเทอร์แอคทีฟที่สร้างขึ้นจะเกินขีดจำกัด Slack Block Kit OpenClaw จะถอยกลับไปใช้ข้อความตอบกลับเดิมแทนการส่ง payload บล็อกที่ไม่ถูกต้อง -## การอนุมัติ exec ใน Slack +## การอนุมัติ Exec ใน Slack -Slack สามารถทำหน้าที่เป็น client การอนุมัติ native พร้อมปุ่มและ interaction แบบ interactive แทนการ fallback ไปยัง Web UI หรือ terminal +Slack สามารถทำหน้าที่เป็นไคลเอนต์อนุมัติ native ที่มีปุ่มและการโต้ตอบแบบอินเทอร์แอคทีฟ แทนการถอยกลับไปใช้ Web UI หรือเทอร์มินัล -- การอนุมัติ exec ใช้ `channels.slack.execApprovals.*` สำหรับการ route DM/channel แบบ native -- การอนุมัติ Plugin ยังสามารถ resolve ผ่านพื้นผิวปุ่ม native ของ Slack เดียวกันได้ เมื่อคำขอมาถึง Slack อยู่แล้วและชนิด approval id คือ `plugin:` -- การตรวจสอบสิทธิ์ผู้อนุมัติยังคงถูกบังคับใช้: เฉพาะผู้ใช้ที่ระบุเป็น approver เท่านั้นที่สามารถ approve หรือ deny คำขอผ่าน Slack ได้ +- การอนุมัติ Exec ใช้ `channels.slack.execApprovals.*` สำหรับการกำหนดเส้นทาง DM/ช่องทางแบบ native +- การอนุมัติ Plugin ยังสามารถแก้ไขผ่านพื้นผิวปุ่ม Slack-native เดียวกันได้ เมื่อคำขอมาถึง Slack อยู่แล้วและชนิด approval id เป็น `plugin:` +- การให้สิทธิ์ผู้อนุมัติยังคงถูกบังคับใช้: เฉพาะผู้ใช้ที่ระบุว่าเป็นผู้อนุมัติเท่านั้นที่สามารถอนุมัติหรือปฏิเสธคำขอผ่าน Slack ได้ -สิ่งนี้ใช้พื้นผิวปุ่มการอนุมัติร่วมแบบเดียวกับ channel อื่น เมื่อเปิดใช้ `interactivity` ในการตั้งค่าแอป Slack ของคุณ prompt การอนุมัติจะ render เป็นปุ่ม Block Kit โดยตรงในการสนทนา +สิ่งนี้ใช้พื้นผิวปุ่มอนุมัติแบบใช้ร่วมกันเดียวกับช่องทางอื่น เมื่อเปิดใช้ `interactivity` ในการตั้งค่าแอป Slack ของคุณ พรอมป์อนุมัติจะเรนเดอร์เป็นปุ่ม Block Kit โดยตรงในการสนทนา เมื่อมีปุ่มเหล่านั้น ปุ่มเหล่านั้นคือ UX การอนุมัติหลัก OpenClaw -ควรรวมคำสั่ง `/approve` แบบ manual เฉพาะเมื่อผลลัพธ์ของเครื่องมือบอกว่าการอนุมัติผ่าน chat -ไม่พร้อมใช้งาน หรือการอนุมัติแบบ manual เป็นเส้นทางเดียวเท่านั้น +ควรรวมคำสั่ง `/approve` แบบแมนนวลเฉพาะเมื่อผลลัพธ์ของเครื่องมือบอกว่าการอนุมัติผ่านแชต +ไม่พร้อมใช้งาน หรือการอนุมัติแบบแมนนวลเป็นเส้นทางเดียวเท่านั้น -เส้นทาง config: +เส้นทางการกำหนดค่า: - `channels.slack.execApprovals.enabled` -- `channels.slack.execApprovals.approvers` (ไม่บังคับ; fallback ไปยัง `commands.ownerAllowFrom` เมื่อเป็นไปได้) +- `channels.slack.execApprovals.approvers` (ไม่บังคับ; ถอยกลับไปใช้ `commands.ownerAllowFrom` เมื่อเป็นไปได้) - `channels.slack.execApprovals.target` (`dm` | `channel` | `both`, ค่าเริ่มต้น: `dm`) - `agentFilter`, `sessionFilter` -Slack จะเปิดใช้การอนุมัติ exec แบบ native โดยอัตโนมัติเมื่อไม่ได้ตั้งค่า `enabled` หรือเป็น `"auto"` และ resolve -approver ได้อย่างน้อยหนึ่งรายการ ตั้งค่า `enabled: false` เพื่อปิดใช้ Slack เป็น client การอนุมัติ native อย่างชัดเจน -ตั้งค่า `enabled: true` เพื่อบังคับเปิดการอนุมัติ native เมื่อ resolve approver ได้ +Slack จะเปิดใช้การอนุมัติ exec แบบ native โดยอัตโนมัติเมื่อไม่ได้ตั้งค่า `enabled` หรือเป็น `"auto"` และแก้ไขผู้อนุมัติได้อย่างน้อยหนึ่งราย +ตั้งค่า `enabled: false` เพื่อปิดใช้ Slack เป็นไคลเอนต์อนุมัติ native อย่างชัดเจน +ตั้งค่า `enabled: true` เพื่อบังคับเปิดการอนุมัติ native เมื่อแก้ไขผู้อนุมัติได้ -พฤติกรรมเริ่มต้นเมื่อไม่มี config การอนุมัติ exec ของ Slack ที่ชัดเจน: +พฤติกรรมเริ่มต้นเมื่อไม่มีการกำหนดค่าการอนุมัติ exec ของ Slack อย่างชัดเจน: ```json5 { @@ -866,8 +885,8 @@ approver ได้อย่างน้อยหนึ่งรายการ } ``` -config แบบ Slack-native ที่ชัดเจนจำเป็นเฉพาะเมื่อคุณต้องการ override approver, เพิ่ม filter, หรือ -เลือกใช้การส่งมอบไปยัง chat ต้นทาง: +การกำหนดค่า Slack-native แบบชัดเจนจำเป็นเฉพาะเมื่อคุณต้องการแทนที่ผู้อนุมัติ เพิ่มตัวกรอง หรือ +เลือกใช้การส่งมอบไปยังแชตต้นทาง: ```json5 { @@ -883,52 +902,52 @@ config แบบ Slack-native ที่ชัดเจนจำเป็นเ } ``` -การส่งต่อ `approvals.exec` แบบ shared แยกต่างหาก ใช้เฉพาะเมื่อ prompt การอนุมัติ exec ต้อง -route ไปยัง chat อื่นหรือเป้าหมาย out-of-band ที่ชัดเจนด้วย การส่งต่อ `approvals.plugin` แบบ shared ก็ -แยกต่างหากเช่นกัน ปุ่ม Slack-native ยังคงสามารถ resolve การอนุมัติ Plugin ได้เมื่อคำขอเหล่านั้นมาถึง +การส่งต่อ `approvals.exec` แบบใช้ร่วมกันแยกต่างหาก ใช้เฉพาะเมื่อพรอมป์อนุมัติ exec ต้อง +กำหนดเส้นทางไปยังแชตอื่นหรือเป้าหมายนอกแบนด์ที่ระบุชัดเจนด้วย การส่งต่อ `approvals.plugin` แบบใช้ร่วมกันก็ +แยกต่างหากเช่นกัน ปุ่ม Slack-native ยังสามารถแก้ไขการอนุมัติ Plugin ได้เมื่อคำขอเหล่านั้นมาถึง Slack อยู่แล้ว -`/approve` ใน chat เดียวกันยังทำงานใน channel และ DM ของ Slack ที่รองรับคำสั่งอยู่แล้ว ดู [การอนุมัติ exec](/th/tools/exec-approvals) สำหรับโมเดลการส่งต่อการอนุมัติแบบเต็ม +`/approve` ในแชตเดียวกันยังใช้ได้ในช่องทาง Slack และ DM ที่รองรับคำสั่งอยู่แล้ว ดู [การอนุมัติ Exec](/th/tools/exec-approvals) สำหรับโมเดลการส่งต่อการอนุมัติฉบับเต็ม -## Events และพฤติกรรมการปฏิบัติการ +## เหตุการณ์และพฤติกรรมการปฏิบัติการ -- การแก้ไข/ลบข้อความจะถูก map เป็น system events -- thread broadcast (การตอบกลับ thread แบบ "Also send to channel") จะถูกประมวลผลเป็นข้อความผู้ใช้ปกติ -- event การเพิ่ม/ลบ reaction จะถูก map เป็น system events -- event สมาชิกเข้าร่วม/ออก, channel ถูกสร้าง/เปลี่ยนชื่อ, และ pin ถูกเพิ่ม/ลบ จะถูก map เป็น system events -- `channel_id_changed` สามารถ migrate คีย์ config ของ channel ได้เมื่อเปิดใช้ `configWrites` -- metadata ของหัวข้อ/วัตถุประสงค์ channel จะถูกปฏิบัติเป็น context ที่ไม่น่าเชื่อถือ และสามารถ inject เข้าไปใน routing context ได้ -- thread starter และการ seed context จากประวัติ thread เริ่มต้นจะถูกกรองด้วย allowlist ผู้ส่งที่กำหนดค่าไว้เมื่อเกี่ยวข้อง -- block actions และ modal interactions จะ emit system events แบบมีโครงสร้าง `Slack interaction: ...` พร้อมฟิลด์ payload ที่ละเอียด: - - block actions: ค่าที่เลือก, label, ค่า picker, และ metadata `workflow_*` - - event modal `view_submission` และ `view_closed` พร้อม metadata channel ที่ถูก route และ input ของฟอร์ม +- การแก้ไข/ลบข้อความถูกแมปเป็นเหตุการณ์ระบบ +- การ broadcast เธรด (การตอบกลับในเธรดแบบ "ส่งไปยังช่องทางด้วย") ถูกประมวลผลเป็นข้อความผู้ใช้ปกติ +- เหตุการณ์เพิ่ม/ลบรีแอคชันถูกแมปเป็นเหตุการณ์ระบบ +- เหตุการณ์สมาชิกเข้าร่วม/ออก ช่องทางถูกสร้าง/เปลี่ยนชื่อ และการเพิ่ม/ลบ pin ถูกแมปเป็นเหตุการณ์ระบบ +- `channel_id_changed` สามารถย้ายคีย์การกำหนดค่าช่องทางเมื่อเปิดใช้ `configWrites` +- เมตาดาต้า topic/purpose ของช่องทางถือเป็นบริบทที่ไม่น่าเชื่อถือและสามารถถูกฉีดเข้าไปในบริบทการกำหนดเส้นทางได้ +- การ seed บริบทของผู้เริ่มเธรดและประวัติเธรดเริ่มต้นจะถูกกรองตาม allowlist ผู้ส่งที่กำหนดค่าไว้เมื่อเกี่ยวข้อง +- Block actions และการโต้ตอบ modal ปล่อยเหตุการณ์ระบบ `Slack interaction: ...` แบบมีโครงสร้าง พร้อมฟิลด์ payload ที่สมบูรณ์: + - block actions: ค่าที่เลือก, labels, ค่า picker และเมตาดาต้า `workflow_*` + - เหตุการณ์ modal `view_submission` และ `view_closed` พร้อมเมตาดาต้าช่องทางที่กำหนดเส้นทางและอินพุตฟอร์ม ## ข้อมูลอ้างอิงการกำหนดค่า ข้อมูลอ้างอิงหลัก: [ข้อมูลอ้างอิงการกำหนดค่า - Slack](/th/gateway/config-channels#slack) - + - mode/auth: `mode`, `botToken`, `appToken`, `signingSecret`, `webhookPath`, `accounts.*` - การเข้าถึง DM: `dm.enabled`, `dmPolicy`, `allowFrom` (legacy: `dm.policy`, `dm.allowFrom`), `dm.groupEnabled`, `dm.groupChannels` -- toggle ความเข้ากันได้: `dangerouslyAllowNameMatching` (break-glass; ปิดไว้เว้นแต่จำเป็น) -- การเข้าถึง channel: `groupPolicy`, `channels.*`, `channels.*.users`, `channels.*.requireMention` -- threading/history: `replyToMode`, `replyToModeByChatType`, `thread.*`, `historyLimit`, `dmHistoryLimit`, `dms.*.historyLimit` -- delivery: `textChunkLimit`, `chunkMode`, `mediaMaxMb`, `streaming`, `streaming.nativeTransport`, `streaming.preview.toolProgress` -- ops/features: `configWrites`, `commands.native`, `slashCommand.*`, `actions.*`, `userToken`, `userTokenReadOnly` +- สวิตช์ความเข้ากันได้: `dangerouslyAllowNameMatching` (break-glass; ปิดไว้เว้นแต่จำเป็น) +- การเข้าถึงช่องทาง: `groupPolicy`, `channels.*`, `channels.*.users`, `channels.*.requireMention` +- เธรด/ประวัติ: `replyToMode`, `replyToModeByChatType`, `thread.*`, `historyLimit`, `dmHistoryLimit`, `dms.*.historyLimit` +- การส่งมอบ: `textChunkLimit`, `chunkMode`, `mediaMaxMb`, `streaming`, `streaming.nativeTransport`, `streaming.preview.toolProgress` +- ops/ฟีเจอร์: `configWrites`, `commands.native`, `slashCommand.*`, `actions.*`, `userToken`, `userTokenReadOnly` ## การแก้ไขปัญหา - + ตรวจสอบตามลำดับ: - `groupPolicy` - - allowlist ของ channel (`channels.slack.channels`) — **คีย์ต้องเป็น channel ID** (`C12345678`) ไม่ใช่ชื่อ (`#channel-name`) คีย์ที่อิงชื่อจะล้มเหลวแบบเงียบภายใต้ `groupPolicy: "allowlist"` เพราะค่าเริ่มต้นของการ route channel ใช้ ID ก่อน วิธีหา ID: คลิกขวาที่ channel ใน Slack → **Copy link** — ค่า `C...` ที่ท้าย URL คือ channel ID + - allowlist ของช่องทาง (`channels.slack.channels`) — **คีย์ต้องเป็น ID ช่องทาง** (`C12345678`) ไม่ใช่ชื่อ (`#channel-name`) คีย์แบบอิงชื่อจะล้มเหลวแบบเงียบภายใต้ `groupPolicy: "allowlist"` เพราะการกำหนดเส้นทางช่องทางใช้ ID เป็นหลักโดยค่าเริ่มต้น วิธีหา ID: คลิกขวาที่ช่องทางใน Slack → **Copy link** — ค่า `C...` ที่ท้าย URL คือ ID ช่องทาง - `requireMention` - - allowlist `users` ต่อ channel + - allowlist `users` รายช่องทาง คำสั่งที่มีประโยชน์: @@ -940,15 +959,15 @@ openclaw doctor - + ตรวจสอบ: - `channels.slack.dm.enabled` - `channels.slack.dmPolicy` (หรือ legacy `channels.slack.dm.policy`) - - การอนุมัติ pairing / รายการ allowlist - - event DM ของ Slack Assistant: log แบบ verbose ที่กล่าวถึง `drop message_changed` - มักหมายความว่า Slack ส่ง event thread ของ Assistant ที่ถูกแก้ไขโดยไม่มี - ผู้ส่งมนุษย์ที่กู้คืนได้ใน metadata ของข้อความ + - การอนุมัติการจับคู่ / รายการ allowlist + - เหตุการณ์ DM ของ Slack Assistant: บันทึก verbose ที่กล่าวถึง `drop message_changed` + มักหมายความว่า Slack ส่งเหตุการณ์เธรด Assistant ที่ถูกแก้ไขโดยไม่มี + ผู้ส่งที่เป็นมนุษย์ซึ่งกู้คืนได้ในเมตาดาต้าข้อความ ```bash openclaw pairing list slack @@ -956,105 +975,105 @@ openclaw pairing list slack - - ตรวจสอบ bot + app token และการเปิดใช้ Socket Mode ในการตั้งค่าแอป Slack + + ตรวจสอบ bot + app tokens และการเปิดใช้ Socket Mode ในการตั้งค่าแอป Slack หาก `openclaw channels status --probe --json` แสดง `botTokenStatus` หรือ - `appTokenStatus: "configured_unavailable"` แสดงว่าบัญชี Slack ถูก - กำหนดค่าแล้ว แต่ runtime ปัจจุบันไม่สามารถ resolve ค่า + `appTokenStatus: "configured_unavailable"` แสดงว่าบัญชี Slack + ถูกกำหนดค่าไว้ แต่ runtime ปัจจุบันไม่สามารถแก้ไขค่า ที่รองรับด้วย SecretRef ได้ - + ตรวจสอบ: - signing secret - - path ของ Webhook + - webhook path - Slack Request URLs (Events + Interactivity + Slash Commands) - `webhookPath` ที่ไม่ซ้ำกันต่อบัญชี HTTP หาก `signingSecretStatus: "configured_unavailable"` ปรากฏใน snapshot - ของบัญชี แสดงว่าบัญชี HTTP ถูกกำหนดค่าแล้ว แต่ runtime ปัจจุบันไม่สามารถ - resolve signing secret ที่รองรับด้วย SecretRef ได้ + ของบัญชี แสดงว่าบัญชี HTTP ถูกกำหนดค่าไว้ แต่ runtime ปัจจุบันไม่สามารถ + แก้ไข signing secret ที่รองรับด้วย SecretRef ได้ - - ตรวจสอบว่าคุณตั้งใจใช้: + + ตรวจสอบว่าคุณตั้งใจใช้แบบใด: - โหมดคำสั่ง native (`channels.slack.commands.native: true`) พร้อมคำสั่ง slash ที่ตรงกันซึ่งลงทะเบียนใน Slack - - หรือโหมดคำสั่ง slash เดี่ยว (`channels.slack.slashCommand.enabled: true`) + - หรือโหมดคำสั่ง slash เดียว (`channels.slack.slashCommand.enabled: true`) - ตรวจสอบ `commands.useAccessGroups` และ allowlist ของ channel/user ด้วย + ตรวจสอบ `commands.useAccessGroups` และ allowlist ของช่องทาง/ผู้ใช้ด้วย -## ข้อมูลอ้างอิง vision สำหรับไฟล์แนบ +## ข้อมูลอ้างอิง vision ของไฟล์แนบ -Slack สามารถแนบสื่อที่ดาวน์โหลดแล้วเข้ากับ turn ของ agent เมื่อการดาวน์โหลดไฟล์ Slack สำเร็จและขีดจำกัดขนาดอนุญาต ไฟล์รูปภาพสามารถส่งผ่านเส้นทางการเข้าใจสื่อ หรือส่งตรงไปยังโมเดลตอบกลับที่รองรับ vision ได้ ส่วนไฟล์อื่นจะถูกเก็บเป็นบริบทไฟล์ที่ดาวน์โหลดได้ แทนที่จะถูกปฏิบัติเป็น input รูปภาพ +Slack สามารถแนบสื่อที่ดาวน์โหลดแล้วเข้ากับรอบของเอเจนต์ได้เมื่อการดาวน์โหลดไฟล์ Slack สำเร็จและข้อจำกัดขนาดอนุญาต ไฟล์ภาพสามารถส่งผ่านเส้นทางการทำความเข้าใจสื่อหรือส่งตรงไปยังโมเดลตอบกลับที่รองรับ vision ได้ ส่วนไฟล์อื่นจะถูกเก็บไว้เป็นบริบทไฟล์ที่ดาวน์โหลดได้ แทนที่จะถูกปฏิบัติเป็นอินพุตรูปภาพ ### ประเภทสื่อที่รองรับ -| ประเภทสื่อ | แหล่งที่มา | พฤติกรรมปัจจุบัน | หมายเหตุ | +| ประเภทสื่อ | แหล่งที่มา | ลักษณะการทำงานปัจจุบัน | หมายเหตุ | | ------------------------------ | -------------------- | --------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | -| รูปภาพ JPEG / PNG / GIF / WebP | URL ไฟล์ Slack | ดาวน์โหลดและแนบเข้ากับรอบสนทนาเพื่อให้จัดการด้วยความสามารถด้านวิชันได้ | ขีดจำกัดต่อไฟล์: `channels.slack.mediaMaxMb` (ค่าเริ่มต้น 20 MB) | -| ไฟล์ PDF | URL ไฟล์ Slack | ดาวน์โหลดและเปิดเผยเป็นบริบทไฟล์สำหรับเครื่องมือ เช่น `download-file` หรือ `pdf` | ขาเข้า Slack ไม่แปลง PDF เป็นอินพุตภาพสำหรับวิชันโดยอัตโนมัติ | -| ไฟล์อื่น ๆ | URL ไฟล์ Slack | ดาวน์โหลดเมื่อเป็นไปได้และเปิดเผยเป็นบริบทไฟล์ | ไฟล์ไบนารีจะไม่ถูกถือเป็นอินพุตรูปภาพ | -| การตอบกลับในเธรด | ไฟล์ของข้อความเริ่มเธรด | ไฟล์จากข้อความรากสามารถเติมเป็นบริบทได้เมื่อการตอบกลับไม่มีสื่อโดยตรง | ข้อความเริ่มที่มีเฉพาะไฟล์ใช้ตัวยึดตำแหน่งไฟล์แนบ | +| รูปภาพ JPEG / PNG / GIF / WebP | URL ไฟล์ Slack | ดาวน์โหลดและแนบเข้ากับเทิร์นเพื่อการจัดการที่รองรับการมองเห็น | ขีดจำกัดต่อไฟล์: `channels.slack.mediaMaxMb` (ค่าเริ่มต้น 20 MB) | +| ไฟล์ PDF | URL ไฟล์ Slack | ดาวน์โหลดและแสดงเป็นบริบทไฟล์สำหรับเครื่องมือ เช่น `download-file` หรือ `pdf` | ขาเข้าของ Slack ไม่แปลง PDF เป็นอินพุตการมองเห็นภาพโดยอัตโนมัติ | +| ไฟล์อื่น | URL ไฟล์ Slack | ดาวน์โหลดเมื่อเป็นไปได้และแสดงเป็นบริบทไฟล์ | ไฟล์ไบนารีจะไม่ถูกปฏิบัติเป็นอินพุตรูปภาพ | +| การตอบกลับในเธรด | ไฟล์ของข้อความเริ่มเธรด | ไฟล์ของข้อความรากสามารถถูกเติมเป็นบริบทได้เมื่อการตอบกลับไม่มีสื่อโดยตรง | ข้อความเริ่มต้นที่มีเฉพาะไฟล์ใช้ตัวยึดตำแหน่งไฟล์แนบ | | ข้อความหลายรูปภาพ | ไฟล์ Slack หลายไฟล์ | แต่ละไฟล์จะถูกประเมินแยกกัน | การประมวลผล Slack จำกัดไว้ที่แปดไฟล์ต่อข้อความ | ### ไปป์ไลน์ขาเข้า -เมื่อมีข้อความ Slack พร้อมไฟล์แนบเข้ามา: +เมื่อข้อความ Slack ที่มีไฟล์แนบมาถึง: 1. OpenClaw ดาวน์โหลดไฟล์จาก URL ส่วนตัวของ Slack โดยใช้โทเค็นบอต (`xoxb-...`) -2. เมื่อสำเร็จ ไฟล์จะถูกเขียนลงในที่เก็บสื่อ -3. พาธสื่อที่ดาวน์โหลดและประเภทเนื้อหาจะถูกเพิ่มลงในบริบทขาเข้า -4. พาธของโมเดล/เครื่องมือที่รองรับรูปภาพสามารถใช้ไฟล์แนบรูปภาพจากบริบทนั้นได้ -5. ไฟล์ที่ไม่ใช่รูปภาพยังคงพร้อมใช้งานเป็นเมตาดาต้าไฟล์หรือการอ้างอิงสื่อสำหรับเครื่องมือที่จัดการไฟล์เหล่านั้นได้ +2. ไฟล์จะถูกเขียนลงในที่จัดเก็บสื่อเมื่อสำเร็จ +3. เส้นทางสื่อที่ดาวน์โหลดแล้วและชนิดเนื้อหาจะถูกเพิ่มลงในบริบทขาเข้า +4. เส้นทางโมเดล/เครื่องมือที่รองรับรูปภาพสามารถใช้ไฟล์แนบรูปภาพจากบริบทนั้นได้ +5. ไฟล์ที่ไม่ใช่รูปภาพยังคงพร้อมใช้งานเป็นเมตาดาต้าไฟล์หรือข้อมูลอ้างอิงสื่อสำหรับเครื่องมือที่จัดการได้ -### การสืบทอดไฟล์แนบจากรากเธรด +### การสืบทอดไฟล์แนบจากรากของเธรด -เมื่อมีข้อความเข้ามาในเธรด (มีพาเรนต์ `thread_ts`): +เมื่อข้อความมาถึงในเธรด (มีพาเรนต์ `thread_ts`): -- หากตัวการตอบกลับเองไม่มีสื่อโดยตรง และข้อความรากที่รวมมามีไฟล์ Slack สามารถเติมไฟล์รากเป็นบริบทข้อความเริ่มเธรดได้ +- หากการตอบกลับเองไม่มีสื่อโดยตรง และข้อความรากที่รวมมามีไฟล์ Slack สามารถเติมไฟล์รากเป็นบริบทเริ่มต้นของเธรดได้ - ไฟล์แนบของการตอบกลับโดยตรงมีลำดับความสำคัญเหนือไฟล์แนบของข้อความราก -- ข้อความรากที่มีเฉพาะไฟล์และไม่มีข้อความจะแสดงด้วยตัวยึดตำแหน่งไฟล์แนบ เพื่อให้กลไกสำรองยังสามารถรวมไฟล์ของข้อความนั้นได้ +- ข้อความรากที่มีเฉพาะไฟล์และไม่มีข้อความจะแสดงด้วยตัวยึดตำแหน่งไฟล์แนบ เพื่อให้ตัวสำรองยังคงรวมไฟล์ของข้อความนั้นได้ ### การจัดการไฟล์แนบหลายรายการ เมื่อข้อความ Slack เดียวมีไฟล์แนบหลายรายการ: - ไฟล์แนบแต่ละรายการจะถูกประมวลผลแยกกันผ่านไปป์ไลน์สื่อ -- การอ้างอิงสื่อที่ดาวน์โหลดจะถูกรวมไว้ในบริบทข้อความ +- ข้อมูลอ้างอิงสื่อที่ดาวน์โหลดแล้วจะถูกรวบรวมลงในบริบทข้อความ - ลำดับการประมวลผลเป็นไปตามลำดับไฟล์ของ Slack ในเพย์โหลดเหตุการณ์ -- ความล้มเหลวในการดาวน์โหลดไฟล์แนบหนึ่งรายการจะไม่บล็อกรายการอื่น +- ความล้มเหลวในการดาวน์โหลดไฟล์แนบหนึ่งรายการไม่บล็อกรายการอื่น -### ขีดจำกัดขนาด การดาวน์โหลด และโมเดล +### ขนาด การดาวน์โหลด และขีดจำกัดของโมเดล - **ขีดจำกัดขนาด**: ค่าเริ่มต้น 20 MB ต่อไฟล์ กำหนดค่าได้ผ่าน `channels.slack.mediaMaxMb` -- **ความล้มเหลวในการดาวน์โหลด**: ไฟล์ที่ Slack ให้บริการไม่ได้, URL หมดอายุ, ไฟล์ที่เข้าถึงไม่ได้, ไฟล์เกินขนาด และการตอบกลับ HTML สำหรับการตรวจสอบสิทธิ์/เข้าสู่ระบบของ Slack จะถูกข้ามแทนที่จะถูกรายงานว่าเป็นรูปแบบที่ไม่รองรับ -- **โมเดลวิชัน**: การวิเคราะห์รูปภาพใช้โมเดลตอบกลับที่ใช้งานอยู่เมื่อรองรับวิชัน หรือใช้โมเดลรูปภาพที่กำหนดค่าไว้ที่ `agents.defaults.imageModel` +- **ความล้มเหลวในการดาวน์โหลด**: ไฟล์ที่ Slack ให้บริการไม่ได้, URL หมดอายุ, ไฟล์ที่เข้าถึงไม่ได้, ไฟล์เกินขนาด และการตอบกลับ HTML สำหรับการยืนยันตัวตน/เข้าสู่ระบบ Slack จะถูกข้ามแทนที่จะถูกรายงานว่าเป็นรูปแบบที่ไม่รองรับ +- **โมเดลการมองเห็น**: การวิเคราะห์รูปภาพใช้โมเดลตอบกลับที่ใช้งานอยู่เมื่อโมเดลนั้นรองรับการมองเห็น หรือใช้โมเดลรูปภาพที่กำหนดค่าไว้ที่ `agents.defaults.imageModel` ### ขีดจำกัดที่ทราบ -| สถานการณ์ | พฤติกรรมปัจจุบัน | วิธีแก้ไขชั่วคราว | +| สถานการณ์ | ลักษณะการทำงานปัจจุบัน | วิธีแก้ไข | | -------------------------------------- | ---------------------------------------------------------------------------- | -------------------------------------------------------------------------- | -| URL ไฟล์ Slack หมดอายุ | ข้ามไฟล์; ไม่แสดงข้อผิดพลาด | อัปโหลดไฟล์ใหม่ใน Slack | -| ไม่ได้กำหนดค่าโมเดลวิชัน | ไฟล์แนบรูปภาพถูกจัดเก็บเป็นการอ้างอิงสื่อ แต่ไม่ถูกวิเคราะห์เป็นรูปภาพ | กำหนดค่า `agents.defaults.imageModel` หรือใช้โมเดลตอบกลับที่รองรับวิชัน | +| URL ไฟล์ Slack หมดอายุ | ข้ามไฟล์; ไม่แสดงข้อผิดพลาด | อัปโหลดไฟล์ใน Slack อีกครั้ง | +| ยังไม่ได้กำหนดค่าโมเดลการมองเห็น | ไฟล์แนบรูปภาพจะถูกจัดเก็บเป็นข้อมูลอ้างอิงสื่อ แต่ไม่ได้วิเคราะห์เป็นรูปภาพ | กำหนดค่า `agents.defaults.imageModel` หรือใช้โมเดลตอบกลับที่รองรับการมองเห็น | | รูปภาพขนาดใหญ่มาก (> 20 MB โดยค่าเริ่มต้น) | ข้ามตามขีดจำกัดขนาด | เพิ่ม `channels.slack.mediaMaxMb` หาก Slack อนุญาต | | ไฟล์แนบที่ส่งต่อ/แชร์ | ข้อความและสื่อรูปภาพ/ไฟล์ที่โฮสต์บน Slack เป็นแบบพยายามให้ดีที่สุด | แชร์ใหม่โดยตรงในเธรด OpenClaw | -| ไฟล์แนบ PDF | จัดเก็บเป็นบริบทไฟล์/สื่อ ไม่ได้ถูกส่งผ่านวิชันรูปภาพโดยอัตโนมัติ | ใช้ `download-file` สำหรับเมตาดาต้าไฟล์ หรือเครื่องมือ `pdf` สำหรับการวิเคราะห์ PDF | +| ไฟล์แนบ PDF | จัดเก็บเป็นบริบทไฟล์/สื่อ ไม่ได้ส่งผ่านการมองเห็นรูปภาพโดยอัตโนมัติ | ใช้ `download-file` สำหรับเมตาดาต้าไฟล์ หรือเครื่องมือ `pdf` สำหรับการวิเคราะห์ PDF | ### เอกสารที่เกี่ยวข้อง -- [ไปป์ไลน์การทำความเข้าใจสื่อ](/th/nodes/media-understanding) +- [ไปป์ไลน์การเข้าใจสื่อ](/th/nodes/media-understanding) - [เครื่องมือ PDF](/th/tools/pdf) -- มหากาพย์: [#51349](https://github.com/openclaw/openclaw/issues/51349) — การเปิดใช้วิชันสำหรับไฟล์แนบ Slack +- มหากาพย์: [#51349](https://github.com/openclaw/openclaw/issues/51349) — การเปิดใช้การมองเห็นไฟล์แนบ Slack - การทดสอบรีเกรสชัน: [#51353](https://github.com/openclaw/openclaw/issues/51353) -- การยืนยันแบบสด: [#51354](https://github.com/openclaw/openclaw/issues/51354) +- การตรวจสอบแบบสด: [#51354](https://github.com/openclaw/openclaw/issues/51354) ## ที่เกี่ยวข้อง @@ -1063,16 +1082,16 @@ Slack สามารถแนบสื่อที่ดาวน์โหล จับคู่ผู้ใช้ Slack กับ Gateway - พฤติกรรมช่องและ DM กลุ่ม + พฤติกรรมของช่องและ DM กลุ่ม กำหนดเส้นทางข้อความขาเข้าไปยังเอเจนต์ - โมเดลภัยคุกคามและการเสริมความปลอดภัย + โมเดลภัยคุกคามและการเสริมความแข็งแกร่ง - เค้าโครงการกำหนดค่าและลำดับความสำคัญ + โครงร่างการกำหนดค่าและลำดับความสำคัญ แคตตาล็อกคำสั่งและพฤติกรรม diff --git a/docs/th/channels/telegram.md b/docs/th/channels/telegram.md index d56ce37bf..912a8f302 100644 --- a/docs/th/channels/telegram.md +++ b/docs/th/channels/telegram.md @@ -1,38 +1,38 @@ --- read_when: - - การทำงานกับฟีเจอร์ Telegram หรือ Webhook -summary: สถานะการรองรับ ความสามารถ และการกำหนดค่าของบอต Telegram + - การทำงานกับฟีเจอร์ของ Telegram หรือ Webhook +summary: สถานะการรองรับบอต Telegram ความสามารถ และการกำหนดค่า title: Telegram x-i18n: - generated_at: "2026-05-03T21:27:19Z" + generated_at: "2026-05-04T07:02:52Z" model: gpt-5.5 provider: openai - source_hash: 528ace9dae29eda22f98cc1436ec16146eb9d83edc73aa6db1ab8283f4f873c0 + source_hash: 6ef1b019a6a0e261b33972b5edffaedd29310b1333d112bade2e79e9d56887c6 source_path: channels/telegram.md workflow: 16 --- -พร้อมใช้งานจริงสำหรับ DM ของบอตและกลุ่มผ่าน grammY โหมดเริ่มต้นคือ long polling; โหมด webhook เป็นตัวเลือกเสริม +พร้อมใช้งานจริงสำหรับ DM ของบอตและกลุ่มผ่าน grammY โหมดเริ่มต้นคือ long polling ส่วนโหมด webhook เป็นตัวเลือก นโยบาย DM เริ่มต้นสำหรับ Telegram คือการจับคู่ - - การวินิจฉัยข้าม Channel และ playbook สำหรับการซ่อมแซม + + การวินิจฉัยข้ามช่องทางและคู่มือการซ่อมแซม - รูปแบบและตัวอย่างการกำหนดค่า Channel แบบครบถ้วน + รูปแบบและตัวอย่างการกำหนดค่าช่องทางแบบครบถ้วน -## การตั้งค่าแบบรวดเร็ว +## การตั้งค่าอย่างรวดเร็ว - เปิด Telegram แล้วแชตกับ **@BotFather** (ยืนยันว่า handle คือ `@BotFather` ทุกตัวอักษร) + เปิด Telegram แล้วแชตกับ **@BotFather** (ยืนยันว่าแฮนเดิลตรงกับ `@BotFather` ทุกตัวอักษร) - เรียกใช้ `/newbot` ทำตาม prompt แล้วบันทึกโทเค็นไว้ + เรียกใช้ `/newbot` ทำตามพรอมต์ แล้วบันทึกโทเค็นไว้ @@ -52,11 +52,11 @@ x-i18n: ``` ค่าทดแทนจาก env: `TELEGRAM_BOT_TOKEN=...` (เฉพาะบัญชีเริ่มต้น) - Telegram **ไม่** ใช้ `openclaw channels login telegram`; ให้กำหนดค่าโทเค็นใน config/env แล้วจึงเริ่ม gateway + Telegram **ไม่** ใช้ `openclaw channels login telegram`; ให้กำหนดค่าโทเค็นใน config/env แล้วเริ่ม gateway - + ```bash openclaw gateway @@ -64,44 +64,44 @@ openclaw pairing list telegram openclaw pairing approve telegram ``` - โค้ดจับคู่หมดอายุหลังจาก 1 ชั่วโมง + รหัสจับคู่หมดอายุหลังจาก 1 ชั่วโมง - - เพิ่มบอตลงในกลุ่มของคุณ แล้วตั้งค่า `channels.telegram.groups` และ `groupPolicy` ให้ตรงกับรูปแบบการเข้าถึงของคุณ + + เพิ่มบอตเข้าไปในกลุ่มของคุณ แล้วตั้งค่า `channels.telegram.groups` และ `groupPolicy` ให้ตรงกับโมเดลการเข้าถึงของคุณ -ลำดับการแก้ค่าโทเค็นรับรู้ระดับบัญชี ในทางปฏิบัติ ค่า config จะมีลำดับเหนือกว่าค่าทดแทนจาก env และ `TELEGRAM_BOT_TOKEN` ใช้กับบัญชีเริ่มต้นเท่านั้น +ลำดับการแก้ค่าโทเค็นรับรู้บัญชี ในทางปฏิบัติ ค่าจาก config จะชนะค่าทดแทนจาก env และ `TELEGRAM_BOT_TOKEN` ใช้กับบัญชีเริ่มต้นเท่านั้น ## การตั้งค่าฝั่ง Telegram - บอต Telegram มีค่าเริ่มต้นเป็น **โหมดความเป็นส่วนตัว** ซึ่งจำกัดข้อความกลุ่มที่บอตได้รับ + บอต Telegram ใช้ **Privacy Mode** เป็นค่าเริ่มต้น ซึ่งจำกัดข้อความกลุ่มที่บอตได้รับ - หากบอตต้องเห็นข้อความทั้งหมดในกลุ่ม ให้ทำอย่างใดอย่างหนึ่ง: + หากบอตต้องเห็นข้อความทั้งหมดในกลุ่ม ให้เลือกอย่างใดอย่างหนึ่ง: - ปิดโหมดความเป็นส่วนตัวผ่าน `/setprivacy` หรือ - ทำให้บอตเป็นผู้ดูแลกลุ่ม - เมื่อสลับโหมดความเป็นส่วนตัว ให้ลบ + เพิ่มบอตกลับเข้าไปใหม่ในแต่ละกลุ่ม เพื่อให้ Telegram นำการเปลี่ยนแปลงไปใช้ + เมื่อสลับโหมดความเป็นส่วนตัว ให้ลบแล้วเพิ่มบอตกลับเข้าไปใหม่ในแต่ละกลุ่ม เพื่อให้ Telegram นำการเปลี่ยนแปลงไปใช้ สถานะผู้ดูแลถูกควบคุมในการตั้งค่ากลุ่ม Telegram - บอตผู้ดูแลจะได้รับข้อความกลุ่มทั้งหมด ซึ่งมีประโยชน์สำหรับพฤติกรรมกลุ่มที่ทำงานตลอดเวลา + บอตที่เป็นผู้ดูแลจะได้รับข้อความกลุ่มทั้งหมด ซึ่งมีประโยชน์สำหรับพฤติกรรมกลุ่มที่เปิดทำงานตลอดเวลา - + - - `/setjoingroups` เพื่ออนุญาต/ปฏิเสธการเพิ่มลงกลุ่ม + - `/setjoingroups` เพื่ออนุญาต/ปฏิเสธการเพิ่มเข้ากลุ่ม - `/setprivacy` สำหรับพฤติกรรมการมองเห็นในกลุ่ม @@ -115,30 +115,30 @@ openclaw pairing approve telegram - `pairing` (ค่าเริ่มต้น) - `allowlist` (ต้องมี ID ผู้ส่งอย่างน้อยหนึ่งรายการใน `allowFrom`) - - `open` (ต้องให้ `allowFrom` มี `"*"`) + - `open` (ต้องให้ `allowFrom` รวม `"*"`) - `disabled` - `dmPolicy: "open"` พร้อม `allowFrom: ["*"]` ทำให้บัญชี Telegram ใด ๆ ที่พบหรือเดาชื่อผู้ใช้ของบอตได้สามารถสั่งงานบอตได้ ใช้เฉพาะกับบอตสาธารณะที่ตั้งใจเปิดให้ใช้ โดยมีเครื่องมือที่จำกัดอย่างเข้มงวดเท่านั้น; บอตเจ้าของคนเดียวควรใช้ `allowlist` พร้อม ID ผู้ใช้แบบตัวเลข + `dmPolicy: "open"` พร้อม `allowFrom: ["*"]` ทำให้บัญชี Telegram ใดก็ตามที่พบหรือเดาชื่อผู้ใช้บอตได้สามารถสั่งงานบอตได้ ใช้เฉพาะกับบอตสาธารณะที่ตั้งใจเปิดให้ใช้งานและมีเครื่องมือที่จำกัดอย่างเข้มงวดเท่านั้น บอตเจ้าของเดียวควรใช้ `allowlist` พร้อม ID ผู้ใช้แบบตัวเลข - `channels.telegram.allowFrom` รับ ID ผู้ใช้ Telegram แบบตัวเลข รองรับ prefix `telegram:` / `tg:` และจะถูกทำให้เป็นรูปแบบมาตรฐาน - ใน config หลายบัญชี ค่า `channels.telegram.allowFrom` ระดับบนสุดที่เข้มงวดจะถูกถือเป็นขอบเขตความปลอดภัย: รายการ `allowFrom: ["*"]` ระดับบัญชีจะไม่ทำให้บัญชีนั้นเป็นสาธารณะ เว้นแต่ allowlist ที่มีผลของบัญชียังคงมี wildcard แบบชัดเจนหลังจากรวมค่าแล้ว + `channels.telegram.allowFrom` รับ ID ผู้ใช้ Telegram แบบตัวเลข รองรับคำนำหน้า `telegram:` / `tg:` และจะทำให้เป็นรูปแบบมาตรฐาน + ในการกำหนดค่าหลายบัญชี `channels.telegram.allowFrom` ระดับบนที่เข้มงวดจะถือเป็นขอบเขตความปลอดภัย: รายการ `allowFrom: ["*"]` ระดับบัญชีจะไม่ทำให้บัญชีนั้นเป็นสาธารณะ เว้นแต่ allowlist ที่มีผลของบัญชียังคงมี wildcard อย่างชัดเจนหลังจากรวมแล้ว `dmPolicy: "allowlist"` พร้อม `allowFrom` ว่างจะบล็อก DM ทั้งหมดและถูกปฏิเสธโดยการตรวจสอบ config - ขั้นตอนตั้งค่าจะขอเฉพาะ ID ผู้ใช้แบบตัวเลข - หากคุณอัปเกรดแล้ว config ของคุณมีรายการ allowlist แบบ `@username` ให้เรียกใช้ `openclaw doctor --fix` เพื่อแก้ค่าเหล่านั้น (พยายามให้ดีที่สุด; ต้องมีโทเค็นบอต Telegram) - หากก่อนหน้านี้คุณพึ่งพาไฟล์ allowlist ของ pairing-store, `openclaw doctor --fix` สามารถกู้คืนรายการเข้าไปใน `channels.telegram.allowFrom` ใน flow แบบ allowlist ได้ (ตัวอย่างเช่นเมื่อ `dmPolicy: "allowlist"` ยังไม่มี ID ที่ระบุไว้อย่างชัดเจน) + การตั้งค่าจะถามเฉพาะ ID ผู้ใช้แบบตัวเลข + หากคุณอัปเกรดแล้ว config มีรายการ allowlist แบบ `@username` ให้เรียกใช้ `openclaw doctor --fix` เพื่อแก้ค่าเหล่านั้น (แบบพยายามให้ดีที่สุด ต้องใช้โทเค็นบอต Telegram) + หากก่อนหน้านี้คุณพึ่งพาไฟล์ allowlist ของ pairing-store, `openclaw doctor --fix` สามารถกู้คืนรายการเข้าไปใน `channels.telegram.allowFrom` ในโฟลว์ allowlist ได้ (เช่น เมื่อ `dmPolicy: "allowlist"` ยังไม่มี ID ที่ระบุอย่างชัดเจน) - สำหรับบอตเจ้าของคนเดียว แนะนำให้ใช้ `dmPolicy: "allowlist"` พร้อม ID `allowFrom` แบบตัวเลขที่ระบุชัดเจน เพื่อให้นโยบายการเข้าถึงคงทนอยู่ใน config (แทนการพึ่งพาการอนุมัติการจับคู่ก่อนหน้า) + สำหรับบอตเจ้าของเดียว ควรใช้ `dmPolicy: "allowlist"` พร้อม ID `allowFrom` แบบตัวเลขที่ระบุอย่างชัดเจน เพื่อให้นโยบายการเข้าถึงคงทนใน config (แทนการพึ่งพาการอนุมัติการจับคู่ก่อนหน้า) - ความสับสนที่พบบ่อย: การอนุมัติการจับคู่ DM ไม่ได้หมายความว่า "ผู้ส่งรายนี้ได้รับอนุญาตทุกที่" - การจับคู่ให้สิทธิ์เข้าถึง DM หากยังไม่มีเจ้าของคำสั่ง การจับคู่ที่อนุมัติครั้งแรกจะตั้งค่า `commands.ownerAllowFrom` ด้วย เพื่อให้คำสั่งเฉพาะเจ้าของและการอนุมัติ exec มีบัญชีผู้ปฏิบัติการที่ชัดเจน - การอนุญาตผู้ส่งในกลุ่มยังคงมาจาก allowlist ที่กำหนดค่าไว้อย่างชัดเจน - หากคุณต้องการ "ฉันได้รับอนุญาตครั้งเดียว แล้วทั้ง DM และคำสั่งในกลุ่มใช้งานได้" ให้ใส่ ID ผู้ใช้ Telegram แบบตัวเลขของคุณใน `channels.telegram.allowFrom`; สำหรับคำสั่งเฉพาะเจ้าของ ตรวจสอบให้แน่ใจว่า `commands.ownerAllowFrom` มี `telegram:` + ความสับสนที่พบบ่อย: การอนุมัติการจับคู่ DM ไม่ได้หมายความว่า "ผู้ส่งนี้ได้รับอนุญาตทุกที่" + การจับคู่ให้สิทธิ์เข้าถึง DM หากยังไม่มีเจ้าของคำสั่ง การจับคู่แรกที่ได้รับอนุมัติจะตั้งค่า `commands.ownerAllowFrom` ด้วย เพื่อให้คำสั่งสำหรับเจ้าของเท่านั้นและการอนุมัติ exec มีบัญชีผู้ปฏิบัติการที่ระบุชัดเจน + การอนุญาตผู้ส่งในกลุ่มยังคงมาจาก allowlist ใน config ที่ระบุชัดเจน + หากคุณต้องการ "ฉันได้รับอนุญาตครั้งเดียว แล้วทั้ง DM และคำสั่งกลุ่มใช้งานได้" ให้ใส่ ID ผู้ใช้ Telegram แบบตัวเลขของคุณใน `channels.telegram.allowFrom`; สำหรับคำสั่งเจ้าของเท่านั้น ให้ตรวจสอบว่า `commands.ownerAllowFrom` มี `telegram:` ### การหา ID ผู้ใช้ Telegram ของคุณ - ปลอดภัยกว่า (ไม่มีบอตบุคคลที่สาม): + วิธีที่ปลอดภัยกว่า (ไม่มีบอตบุคคลที่สาม): - 1. ส่ง DM ถึงบอตของคุณ + 1. ส่ง DM ไปยังบอตของคุณ 2. เรียกใช้ `openclaw logs --follow` 3. อ่าน `from.id` @@ -153,12 +153,12 @@ curl "https://api.telegram.org/bot/getUpdates" - มีการควบคุมสองส่วนที่ใช้ร่วมกัน: + มีตัวควบคุมสองรายการที่ใช้ร่วมกัน: 1. **กลุ่มใดได้รับอนุญาต** (`channels.telegram.groups`) - ไม่มี config `groups`: - - พร้อม `groupPolicy: "open"`: กลุ่มใด ๆ ผ่านการตรวจสอบ group-ID ได้ - - พร้อม `groupPolicy: "allowlist"` (ค่าเริ่มต้น): กลุ่มจะถูกบล็อกจนกว่าคุณจะเพิ่มรายการ `groups` (หรือ `"*"`) + - เมื่อใช้ `groupPolicy: "open"`: กลุ่มใดก็ผ่านการตรวจสอบ group-ID ได้ + - เมื่อใช้ `groupPolicy: "allowlist"` (ค่าเริ่มต้น): กลุ่มจะถูกบล็อกจนกว่าคุณจะเพิ่มรายการ `groups` (หรือ `"*"`) - กำหนดค่า `groups` แล้ว: ทำหน้าที่เป็น allowlist (ID ที่ระบุชัดเจนหรือ `"*"`) 2. **ผู้ส่งใดได้รับอนุญาตในกลุ่ม** (`channels.telegram.groupPolicy`) @@ -167,16 +167,16 @@ curl "https://api.telegram.org/bot/getUpdates" - `disabled` `groupAllowFrom` ใช้สำหรับการกรองผู้ส่งในกลุ่ม หากไม่ได้ตั้งค่า Telegram จะ fallback ไปที่ `allowFrom` - รายการ `groupAllowFrom` ควรเป็น ID ผู้ใช้ Telegram แบบตัวเลข (`telegram:` / `tg:` prefix จะถูกทำให้เป็นรูปแบบมาตรฐาน) - อย่าใส่ ID แชตของกลุ่มหรือ supergroup ของ Telegram ใน `groupAllowFrom` ID แชตติดลบต้องอยู่ใต้ `channels.telegram.groups` + รายการ `groupAllowFrom` ควรเป็น ID ผู้ใช้ Telegram แบบตัวเลข (คำนำหน้า `telegram:` / `tg:` จะถูกทำให้เป็นรูปแบบมาตรฐาน) + อย่าใส่ ID แชตของกลุ่มหรือ supergroup Telegram ใน `groupAllowFrom` ID แชตค่าลบต้องอยู่ใต้ `channels.telegram.groups` รายการที่ไม่ใช่ตัวเลขจะถูกละเว้นสำหรับการอนุญาตผู้ส่ง - ขอบเขตความปลอดภัย (`2026.2.25+`): auth ผู้ส่งในกลุ่ม **ไม่** สืบทอดการอนุมัติจาก pairing-store ของ DM - การจับคู่ยังเป็นเฉพาะ DM เท่านั้น สำหรับกลุ่ม ให้ตั้งค่า `groupAllowFrom` หรือ `allowFrom` รายกลุ่ม/รายหัวข้อ + ขอบเขตความปลอดภัย (`2026.2.25+`): การตรวจสอบสิทธิ์ผู้ส่งในกลุ่ม **ไม่** สืบทอดการอนุมัติจาก DM pairing-store + การจับคู่ยังคงเป็นเฉพาะ DM เท่านั้น สำหรับกลุ่ม ให้ตั้งค่า `groupAllowFrom` หรือ `allowFrom` ต่อกลุ่ม/ต่อหัวข้อ หากไม่ได้ตั้งค่า `groupAllowFrom`, Telegram จะ fallback ไปที่ config `allowFrom` ไม่ใช่ pairing store - รูปแบบที่ใช้ได้จริงสำหรับบอตเจ้าของคนเดียว: ตั้งค่า ID ผู้ใช้ของคุณใน `channels.telegram.allowFrom` ปล่อย `groupAllowFrom` ให้ไม่ได้ตั้งค่า และอนุญาตกลุ่มเป้าหมายใต้ `channels.telegram.groups` - หมายเหตุ runtime: หาก `channels.telegram` หายไปทั้งหมด runtime จะมีค่าเริ่มต้นแบบ fail-closed เป็น `groupPolicy="allowlist"` เว้นแต่จะตั้งค่า `channels.defaults.groupPolicy` ไว้อย่างชัดเจน + รูปแบบใช้งานจริงสำหรับบอตเจ้าของเดียว: ตั้งค่า ID ผู้ใช้ของคุณใน `channels.telegram.allowFrom`, ปล่อย `groupAllowFrom` ไว้ไม่ตั้งค่า และอนุญาตกลุ่มเป้าหมายใต้ `channels.telegram.groups` + หมายเหตุรันไทม์: หาก `channels.telegram` หายไปทั้งหมด รันไทม์จะใช้ค่าเริ่มต้นแบบ fail-closed `groupPolicy="allowlist"` เว้นแต่ตั้งค่า `channels.defaults.groupPolicy` ไว้อย่างชัดเจน - ตัวอย่าง: อนุญาตสมาชิกใดก็ได้ในกลุ่มหนึ่งที่ระบุ: + ตัวอย่าง: อนุญาตสมาชิกใดก็ได้ในกลุ่มเฉพาะหนึ่งกลุ่ม: ```json5 { @@ -193,7 +193,7 @@ curl "https://api.telegram.org/bot/getUpdates" } ``` - ตัวอย่าง: อนุญาตเฉพาะผู้ใช้ที่ระบุภายในกลุ่มหนึ่งที่ระบุ: + ตัวอย่าง: อนุญาตเฉพาะผู้ใช้ที่ระบุภายในกลุ่มเฉพาะหนึ่งกลุ่ม: ```json5 { @@ -213,32 +213,32 @@ curl "https://api.telegram.org/bot/getUpdates" ข้อผิดพลาดที่พบบ่อย: `groupAllowFrom` ไม่ใช่ allowlist ของกลุ่ม Telegram - - ใส่ ID แชตของกลุ่มหรือ supergroup ของ Telegram ที่ติดลบ เช่น `-1001234567890` ไว้ใต้ `channels.telegram.groups` - - ใส่ ID ผู้ใช้ Telegram เช่น `8734062810` ไว้ใต้ `groupAllowFrom` เมื่อคุณต้องการจำกัดว่าคนใดในกลุ่มที่ได้รับอนุญาตสามารถเรียกบอตได้ - - ใช้ `groupAllowFrom: ["*"]` เฉพาะเมื่อคุณต้องการให้สมาชิกใดก็ได้ของกลุ่มที่ได้รับอนุญาตสามารถคุยกับบอตได้ + - ใส่ ID แชตกลุ่มหรือ supergroup Telegram ที่เป็นค่าลบ เช่น `-1001234567890` ใต้ `channels.telegram.groups` + - ใส่ ID ผู้ใช้ Telegram เช่น `8734062810` ใต้ `groupAllowFrom` เมื่อคุณต้องการจำกัดว่าคนใดภายในกลุ่มที่อนุญาตสามารถเรียกบอตได้ + - ใช้ `groupAllowFrom: ["*"]` เฉพาะเมื่อคุณต้องการให้สมาชิกใดก็ได้ของกลุ่มที่อนุญาตสามารถคุยกับบอตได้ - การตอบกลับในกลุ่มต้องมี mention ตามค่าเริ่มต้น + การตอบกลับในกลุ่มต้องมีการ mention เป็นค่าเริ่มต้น - mention สามารถมาจาก: + การ mention อาจมาจาก: - - mention แบบ native `@botusername` หรือ - - รูปแบบ mention ใน: + - การ mention แบบเนทีฟ `@botusername` หรือ + - รูปแบบการ mention ใน: - `agents.list[].groupChat.mentionPatterns` - `messages.groupChat.mentionPatterns` - ตัวสลับคำสั่งระดับ session: + ตัวสลับคำสั่งระดับเซสชัน: - `/activation always` - `/activation mention` - สิ่งเหล่านี้อัปเดตเฉพาะสถานะ session เท่านั้น ใช้ config เพื่อความคงทน + สิ่งเหล่านี้อัปเดตเฉพาะสถานะเซสชัน ใช้ config เพื่อให้คงอยู่ถาวร - ตัวอย่าง config แบบคงทน: + ตัวอย่าง config ถาวร: ```json5 { @@ -254,42 +254,43 @@ curl "https://api.telegram.org/bot/getUpdates" การหา ID แชตของกลุ่ม: - - forward ข้อความกลุ่มไปยัง `@userinfobot` / `@getidsbot` + - ส่งต่อข้อความกลุ่มไปที่ `@userinfobot` / `@getidsbot` - หรืออ่าน `chat.id` จาก `openclaw logs --follow` - หรือตรวจสอบ Bot API `getUpdates` -## พฤติกรรม runtime +## พฤติกรรมรันไทม์ -- Telegram ถูกเป็นเจ้าของโดยโปรเซส gateway -- การกำหนดเส้นทางเป็นแบบกำหนดแน่นอน: ข้อความขาเข้าจาก Telegram จะตอบกลับไปยัง Telegram (โมเดลไม่ได้เลือก Channel) -- ข้อความขาเข้าถูกทำให้เป็นรูปแบบมาตรฐานใน envelope Channel ที่ใช้ร่วมกัน พร้อม metadata การตอบกลับและ placeholder ของสื่อ -- session ของกลุ่มถูกแยกตาม ID กลุ่ม หัวข้อฟอรัมจะต่อท้าย `:topic:` เพื่อแยกหัวข้อออกจากกัน -- ข้อความ DM สามารถมี `message_thread_id`; OpenClaw จะรักษา thread ID ไว้สำหรับการตอบกลับ แต่คง DM ไว้บน session แบบแบนตามค่าเริ่มต้น กำหนดค่า `channels.telegram.dm.threadReplies: "inbound"`, `channels.telegram.direct..threadReplies: "inbound"`, `requireTopic: true` หรือ config หัวข้อที่ตรงกัน เมื่อคุณตั้งใจต้องการการแยก session ของหัวข้อ DM -- Long polling ใช้ grammY runner พร้อมการจัดลำดับต่อแชต/ต่อ thread concurrency ของ runner sink โดยรวมใช้ `agents.defaults.maxConcurrent` -- Long polling ถูกป้องกันภายในแต่ละโปรเซส gateway เพื่อให้ poller ที่ active เพียงหนึ่งตัวใช้โทเค็นบอตได้ในแต่ละครั้ง หากคุณยังเห็นข้อขัดแย้ง `getUpdates` 409 น่าจะมี OpenClaw gateway อื่น, script หรือ poller ภายนอกกำลังใช้โทเค็นเดียวกันอยู่ -- watchdog ของ long-polling จะทริกเกอร์การ restart ตามค่าเริ่มต้นหลังจากไม่มี liveness ของ `getUpdates` ที่เสร็จสมบูรณ์เป็นเวลา 120 วินาที เพิ่ม `channels.telegram.pollingStallThresholdMs` เฉพาะเมื่อ deployment ของคุณยังเห็นการ restart จาก polling-stall แบบ false ระหว่างงานที่ใช้เวลานาน ค่านี้เป็นมิลลิวินาทีและอนุญาตตั้งแต่ `30000` ถึง `600000`; รองรับ override รายบัญชี -- Telegram Bot API ไม่มีการรองรับ read-receipt (`sendReadReceipts` ใช้ไม่ได้) +- Telegram ถูกเป็นเจ้าของโดยกระบวนการ gateway +- การกำหนดเส้นทางเป็นแบบกำหนดแน่นอน: ข้อความขาเข้า Telegram จะตอบกลับไปยัง Telegram (โมเดลไม่ได้เลือกช่องทาง) +- ข้อความขาเข้าถูกทำให้เป็นรูปแบบมาตรฐานใน envelope ช่องทางร่วม พร้อม metadata การตอบกลับและ placeholder สื่อ +- เซสชันกลุ่มแยกตาม ID กลุ่ม หัวข้อฟอรัมจะเติม `:topic:` เพื่อแยกหัวข้อออกจากกัน +- ข้อความ DM สามารถมี `message_thread_id`; OpenClaw จะรักษา ID เธรดไว้สำหรับการตอบกลับ แต่คง DM ไว้บนเซสชันแบบแบนเป็นค่าเริ่มต้น กำหนดค่า `channels.telegram.dm.threadReplies: "inbound"`, `channels.telegram.direct..threadReplies: "inbound"`, `requireTopic: true` หรือ config หัวข้อที่ตรงกัน เมื่อคุณตั้งใจต้องการแยกเซสชันหัวข้อ DM +- Long polling ใช้ grammY runner พร้อมการเรียงลำดับต่อแชต/ต่อเธรด ความพร้อมกันของ runner sink โดยรวมใช้ `agents.defaults.maxConcurrent` +- Long polling ถูกป้องกันภายในแต่ละกระบวนการ gateway เพื่อให้มี active poller เพียงตัวเดียวที่ใช้โทเค็นบอตได้ในแต่ละครั้ง หากคุณยังเห็นข้อขัดแย้ง `getUpdates` 409 อาจมี OpenClaw gateway, สคริปต์ หรือ poller ภายนอกอีกตัวที่ใช้โทเค็นเดียวกันอยู่ +- การรีสตาร์ทจาก watchdog ของ long-polling จะถูกทริกเกอร์หลังจากไม่มี liveness ของ `getUpdates` ที่เสร็จสมบูรณ์เป็นเวลา 120 วินาทีโดยค่าเริ่มต้น เพิ่ม `channels.telegram.pollingStallThresholdMs` เฉพาะเมื่อ deployment ของคุณยังเห็นการรีสตาร์ทจาก polling-stall แบบ false ระหว่างงานที่ใช้เวลานาน ค่านี้เป็นมิลลิวินาทีและอนุญาตตั้งแต่ `30000` ถึง `600000`; รองรับการ override ต่อบัญชี +- Telegram Bot API ไม่รองรับ read-receipt (`sendReadReceipts` ไม่ใช้กับกรณีนี้) ## อ้างอิงฟีเจอร์ - - OpenClaw สามารถสตรีมคำตอบบางส่วนแบบ real time ได้: + + OpenClaw สามารถสตรีมคำตอบบางส่วนแบบเรียลไทม์: - - แชตโดยตรง: ข้อความตัวอย่าง + `editMessageText` - - กลุ่ม/หัวข้อ: ข้อความตัวอย่าง + `editMessageText` + - แชตโดยตรง: ข้อความพรีวิว + `editMessageText` + - กลุ่ม/หัวข้อ: ข้อความพรีวิว + `editMessageText` ข้อกำหนด: - `channels.telegram.streaming` คือ `off | partial | block | progress` (ค่าเริ่มต้น: `partial`) - - `progress` เก็บ draft สถานะที่แก้ไขได้หนึ่งรายการและอัปเดตด้วยความคืบหน้าของเครื่องมือจนกว่าจะส่งข้อความสุดท้าย - - `streaming.preview.toolProgress` ควบคุมว่าการอัปเดตเครื่องมือ/ความคืบหน้าจะใช้ข้อความตัวอย่างที่แก้ไขข้อความเดิมซ้ำหรือไม่ (ค่าเริ่มต้น: `true` เมื่อ preview streaming ทำงานอยู่) - - ค่าเดิม `channels.telegram.streamMode` และค่า boolean ของ `streaming` จะถูกตรวจพบ; เรียกใช้ `openclaw doctor --fix` เพื่อย้ายค่าเหล่านั้นไปยัง `channels.telegram.streaming.mode` + - `progress` เก็บแบบร่างสถานะที่แก้ไขได้หนึ่งรายการและอัปเดตด้วยความคืบหน้าของเครื่องมือจนถึงการส่งขั้นสุดท้าย + - `streaming.preview.toolProgress` ควบคุมว่าการอัปเดตเครื่องมือ/ความคืบหน้าจะใช้ข้อความพรีวิวที่แก้ไขข้อความเดิมซ้ำหรือไม่ (ค่าเริ่มต้น: `true` เมื่อ preview streaming ทำงาน) + - `streaming.preview.commandText` ควบคุมรายละเอียดคำสั่ง/exec ภายในบรรทัดความคืบหน้าของเครื่องมือเหล่านั้น: `raw` (ค่าเริ่มต้น รักษาพฤติกรรมที่ปล่อยแล้ว) หรือ `status` (เฉพาะป้ายกำกับเครื่องมือ) + - ระบบตรวจพบ `channels.telegram.streamMode` แบบเดิมและค่า `streaming` แบบบูลีน ให้เรียกใช้ `openclaw doctor --fix` เพื่อย้ายไปยัง `channels.telegram.streaming.mode` - การอัปเดตตัวอย่างความคืบหน้าของเครื่องมือคือบรรทัดสถานะสั้น ๆ ที่แสดงระหว่างที่เครื่องมือทำงาน เช่น การเรียกใช้คำสั่ง การอ่านไฟล์ การอัปเดตการวางแผน หรือสรุป patch Telegram เปิดใช้สิ่งเหล่านี้ตามค่าเริ่มต้นเพื่อให้ตรงกับพฤติกรรม OpenClaw ที่เผยแพร่ตั้งแต่ `v2026.4.22` และใหม่กว่า หากต้องการคงตัวอย่างที่แก้ไขได้สำหรับข้อความคำตอบ แต่ซ่อนบรรทัดความคืบหน้าของเครื่องมือ ให้ตั้งค่า: + การอัปเดตพรีวิวความคืบหน้าของเครื่องมือคือบรรทัดสถานะสั้น ๆ ที่แสดงระหว่างที่เครื่องมือทำงาน เช่น การเรียกใช้คำสั่ง การอ่านไฟล์ การอัปเดตการวางแผน หรือสรุปแพตช์ Telegram เปิดใช้สิ่งเหล่านี้เป็นค่าเริ่มต้นเพื่อให้ตรงกับพฤติกรรม OpenClaw ที่ปล่อยแล้วตั้งแต่ `v2026.4.22` เป็นต้นไป หากต้องการเก็บพรีวิวที่แก้ไขได้สำหรับข้อความคำตอบแต่ซ่อนบรรทัดความคืบหน้าของเครื่องมือ ให้ตั้งค่า: ```json { @@ -306,25 +307,61 @@ curl "https://api.telegram.org/bot/getUpdates" } ``` - ใช้ `streaming.mode: "off"` เฉพาะเมื่อคุณต้องการส่งเฉพาะผลลัพธ์สุดท้ายเท่านั้น: การแก้ไขพรีวิวของ Telegram จะถูกปิด และข้อความทั่วไปเกี่ยวกับเครื่องมือ/ความคืบหน้าจะถูกระงับแทนที่จะส่งเป็นข้อความสถานะแยกต่างหาก พรอมป์ขออนุมัติ เพย์โหลดสื่อ และข้อผิดพลาดจะยังถูกส่งผ่านการส่งผลลัพธ์สุดท้ายตามปกติ ใช้ `streaming.preview.toolProgress: false` เมื่อคุณต้องการคงการแก้ไขพรีวิวคำตอบไว้เท่านั้น พร้อมซ่อนบรรทัดสถานะความคืบหน้าของเครื่องมือ + หากต้องการให้ความคืบหน้าของเครื่องมือยังมองเห็นได้แต่ซ่อนข้อความคำสั่ง/exec ให้ตั้งค่า: + + ```json + { + "channels": { + "telegram": { + "streaming": { + "mode": "partial", + "preview": { + "commandText": "status" + } + } + } + } + } + ``` + + สำหรับโหมดร่างความคืบหน้า ให้วางนโยบายข้อความคำสั่งเดียวกันไว้ใต้ `streaming.progress`: + + ```json + { + "channels": { + "telegram": { + "streaming": { + "mode": "progress", + "progress": { + "toolProgress": true, + "commandText": "status" + } + } + } + } + } + ``` + + ใช้ `streaming.mode: "off"` เฉพาะเมื่อคุณต้องการส่งเฉพาะคำตอบสุดท้ายเท่านั้น: การแก้ไขตัวอย่างก่อนส่งของ Telegram จะถูกปิดใช้งาน และข้อความทั่วไปจากเครื่องมือ/ความคืบหน้าจะถูกระงับแทนการส่งเป็นข้อความสถานะแยกต่างหาก พรอมต์ขออนุมัติ เพย์โหลดสื่อ และข้อผิดพลาดยังคงถูกส่งผ่านการส่งคำตอบสุดท้ายตามปกติ ใช้ `streaming.preview.toolProgress: false` เมื่อคุณต้องการเก็บเฉพาะการแก้ไขตัวอย่างคำตอบ แต่ซ่อนบรรทัดสถานะความคืบหน้าของเครื่องมือ - การตอบกลับคำพูดที่เลือกของ Telegram เป็นข้อยกเว้น เมื่อ `replyToMode` เป็น `"first"`, `"all"` หรือ `"batched"` และข้อความขาเข้ามีข้อความคำพูดที่เลือก OpenClaw จะส่งคำตอบสุดท้ายผ่านเส้นทางการตอบกลับคำพูดแบบเนทีฟของ Telegram แทนการแก้ไขพรีวิวคำตอบ ดังนั้น `streaming.preview.toolProgress` จึงไม่สามารถแสดงบรรทัดสถานะสั้นๆ สำหรับเทิร์นนั้นได้ การตอบกลับข้อความปัจจุบันที่ไม่มีข้อความคำพูดที่เลือกยังคงใช้การสตรีมพรีวิวได้ ตั้งค่า `replyToMode: "off"` เมื่อการมองเห็นความคืบหน้าของเครื่องมือสำคัญกว่าการตอบกลับคำพูดแบบเนทีฟ หรือตั้งค่า `streaming.preview.toolProgress: false` เพื่อยอมรับข้อแลกเปลี่ยนนี้ + การตอบกลับด้วยข้อความอ้างอิงที่เลือกใน Telegram เป็นข้อยกเว้น เมื่อ `replyToMode` เป็น `"first"`, `"all"` หรือ `"batched"` และข้อความขาเข้ามีข้อความอ้างอิงที่เลือกไว้ OpenClaw จะส่งคำตอบสุดท้ายผ่านเส้นทางการตอบกลับแบบอ้างอิงเนทีฟของ Telegram แทนการแก้ไขตัวอย่างคำตอบ ดังนั้น `streaming.preview.toolProgress` จึงไม่สามารถแสดงบรรทัดสถานะสั้น ๆ สำหรับรอบนั้นได้ การตอบกลับข้อความปัจจุบันที่ไม่มีข้อความอ้างอิงที่เลือกไว้ยังคงใช้การสตรีมตัวอย่างได้ ตั้งค่า `replyToMode: "off"` เมื่อการมองเห็นความคืบหน้าของเครื่องมือสำคัญกว่าการตอบกลับแบบอ้างอิงเนทีฟ หรือตั้งค่า `streaming.preview.toolProgress: false` เพื่อยอมรับข้อแลกเปลี่ยนนี้ สำหรับการตอบกลับแบบข้อความเท่านั้น: - - พรีวิวสั้นใน DM/กลุ่ม/หัวข้อ: OpenClaw จะคงข้อความพรีวิวเดิมไว้และแก้ไขครั้งสุดท้ายในที่เดิม เว้นแต่ว่ามีข้อความที่มองเห็นได้ซึ่งไม่ใช่พรีวิวถูกส่งหลังจากพรีวิวปรากฏ - - พรีวิวที่ตามด้วยเอาต์พุตที่มองเห็นได้ซึ่งไม่ใช่พรีวิว: OpenClaw จะส่งการตอบกลับที่เสร็จสมบูรณ์เป็นข้อความสุดท้ายใหม่ และล้างพรีวิวเก่าออก เพื่อให้คำตอบสุดท้ายปรากฏหลังเอาต์พุตระหว่างทาง - - พรีวิวที่เก่ากว่าประมาณหนึ่งนาที: OpenClaw จะส่งการตอบกลับที่เสร็จสมบูรณ์เป็นข้อความสุดท้ายใหม่ แล้วจึงล้างพรีวิวออก เพื่อให้เวลาที่มองเห็นได้ของ Telegram สะท้อนเวลาที่เสร็จสมบูรณ์แทนเวลาที่สร้างพรีวิว + - ตัวอย่างสั้นใน DM/กลุ่ม/หัวข้อ: OpenClaw จะเก็บข้อความตัวอย่างเดิมไว้และแก้ไขครั้งสุดท้ายในตำแหน่งเดิม เว้นแต่จะมีข้อความที่มองเห็นได้ซึ่งไม่ใช่ตัวอย่างถูกส่งหลังจากตัวอย่างปรากฏขึ้น + - ตัวอย่างที่ตามด้วยเอาต์พุตที่มองเห็นได้ซึ่งไม่ใช่ตัวอย่าง: OpenClaw จะส่งคำตอบที่เสร็จสมบูรณ์เป็นข้อความสุดท้ายใหม่ และล้างตัวอย่างเก่า เพื่อให้คำตอบสุดท้ายปรากฏหลังเอาต์พุตระหว่างทาง + - ตัวอย่างที่เก่ากว่าประมาณหนึ่งนาที: OpenClaw จะส่งคำตอบที่เสร็จสมบูรณ์เป็นข้อความสุดท้ายใหม่ แล้วล้างตัวอย่าง เพื่อให้เวลาประทับที่มองเห็นได้ของ Telegram สะท้อนเวลาที่เสร็จสมบูรณ์แทนเวลาที่สร้างตัวอย่าง - สำหรับการตอบกลับที่ซับซ้อน (เช่น เพย์โหลดสื่อ) OpenClaw จะย้อนกลับไปใช้การส่งผลลัพธ์สุดท้ายตามปกติ แล้วจึงล้างข้อความพรีวิวออก + สำหรับการตอบกลับที่ซับซ้อน (เช่น เพย์โหลดสื่อ) OpenClaw จะย้อนกลับไปใช้การส่งคำตอบสุดท้ายตามปกติ แล้วล้างข้อความตัวอย่าง - การสตรีมพรีวิวแยกจากการสตรีมบล็อก เมื่อเปิดใช้การสตรีมบล็อกอย่างชัดเจนสำหรับ Telegram OpenClaw จะข้ามสตรีมพรีวิวเพื่อหลีกเลี่ยงการสตรีมซ้ำ + การสตรีมตัวอย่างแยกจากการสตรีมบล็อก เมื่อเปิดใช้งานการสตรีมบล็อกสำหรับ Telegram อย่างชัดเจน OpenClaw จะข้ามสตรีมตัวอย่างเพื่อหลีกเลี่ยงการสตรีมซ้ำ สตรีมการให้เหตุผลเฉพาะ Telegram: - - `/reasoning stream` ส่งการให้เหตุผลไปยังพรีวิวสดระหว่างสร้างคำตอบ + - `/reasoning stream` ส่งการให้เหตุผลไปยังตัวอย่างสดระหว่างการสร้าง + - ตัวอย่างการให้เหตุผลจะถูกลบหลังจากส่งคำตอบสุดท้าย ใช้ `/reasoning on` เมื่อควรให้การให้เหตุผลยังคงมองเห็นได้ - คำตอบสุดท้ายจะถูกส่งโดยไม่มีข้อความการให้เหตุผล @@ -332,20 +369,20 @@ curl "https://api.telegram.org/bot/getUpdates" ข้อความขาออกใช้ Telegram `parse_mode: "HTML"` - - ข้อความแบบคล้าย Markdown จะถูกเรนเดอร์เป็น HTML ที่ปลอดภัยสำหรับ Telegram - - HTML ดิบจากโมเดลจะถูก escape เพื่อลดความล้มเหลวในการแยกวิเคราะห์ของ Telegram - - หาก Telegram ปฏิเสธ HTML ที่แยกวิเคราะห์แล้ว OpenClaw จะลองใหม่เป็นข้อความธรรมดา + - ข้อความลักษณะ Markdown จะถูกเรนเดอร์เป็น HTML ที่ปลอดภัยสำหรับ Telegram + - HTML ดิบจากโมเดลจะถูก escape เพื่อลดความล้มเหลวในการ parse ของ Telegram + - หาก Telegram ปฏิเสธ HTML ที่ parse แล้ว OpenClaw จะลองอีกครั้งเป็นข้อความธรรมดา - พรีวิวลิงก์เปิดใช้ตามค่าเริ่มต้น และปิดได้ด้วย `channels.telegram.linkPreview: false` + ตัวอย่างลิงก์เปิดใช้งานโดยค่าเริ่มต้น และสามารถปิดใช้งานได้ด้วย `channels.telegram.linkPreview: false` - การลงทะเบียนเมนูคำสั่งของ Telegram จะถูกจัดการตอนเริ่มต้นด้วย `setMyCommands` + การลงทะเบียนเมนูคำสั่งของ Telegram จัดการตอนเริ่มต้นด้วย `setMyCommands` ค่าเริ่มต้นของคำสั่งเนทีฟ: - - `commands.native: "auto"` เปิดใช้คำสั่งเนทีฟสำหรับ Telegram + - `commands.native: "auto"` เปิดใช้งานคำสั่งเนทีฟสำหรับ Telegram เพิ่มรายการเมนูคำสั่งกำหนดเอง: @@ -364,47 +401,47 @@ curl "https://api.telegram.org/bot/getUpdates" กฎ: - - ชื่อจะถูกทำให้เป็นรูปแบบมาตรฐาน (ตัด `/` นำหน้าออก, แปลงเป็นตัวพิมพ์เล็ก) + - ชื่อจะถูกปรับให้อยู่ในรูปมาตรฐาน (ตัด `/` นำหน้าออก, แปลงเป็นตัวพิมพ์เล็ก) - รูปแบบที่ถูกต้อง: `a-z`, `0-9`, `_`, ความยาว `1..32` - - คำสั่งกำหนดเองไม่สามารถแทนที่คำสั่งเนทีฟได้ - - รายการที่ขัดแย้ง/ซ้ำจะถูกข้ามและบันทึกลงล็อก + - คำสั่งกำหนดเองไม่สามารถเขียนทับคำสั่งเนทีฟได้ + - ความขัดแย้ง/รายการซ้ำจะถูกข้ามและบันทึกในล็อก หมายเหตุ: - - คำสั่งกำหนดเองเป็นเพียงรายการเมนูเท่านั้น; ไม่ได้ติดตั้งพฤติกรรมให้อัตโนมัติ - - คำสั่งของ plugin/skill ยังคงทำงานได้เมื่อพิมพ์ แม้จะไม่แสดงในเมนู Telegram + - คำสั่งกำหนดเองเป็นเพียงรายการเมนูเท่านั้น และไม่ได้ทำให้มีพฤติกรรมโดยอัตโนมัติ + - คำสั่งของ plugin/skill ยังสามารถทำงานได้เมื่อพิมพ์ แม้จะไม่แสดงในเมนู Telegram - หากปิดใช้คำสั่งเนทีฟ คำสั่งในตัวจะถูกนำออก คำสั่งกำหนดเอง/plugin อาจยังลงทะเบียนได้หากกำหนดค่าไว้ + หากปิดใช้งานคำสั่งเนทีฟ รายการในตัวจะถูกลบออก คำสั่งกำหนดเอง/plugin อาจยังลงทะเบียนได้หากกำหนดค่าไว้ - ความล้มเหลวทั่วไปในการตั้งค่า: + ความล้มเหลวในการตั้งค่าที่พบบ่อย: - - `setMyCommands failed` พร้อม `BOT_COMMANDS_TOO_MUCH` หมายความว่าเมนู Telegram ยังคงล้นหลังจากตัดรายการแล้ว; ลดจำนวนคำสั่ง plugin/skill/กำหนดเอง หรือปิดใช้ `channels.telegram.commands.native` - - `deleteWebhook`, `deleteMyCommands` หรือ `setMyCommands` ล้มเหลวด้วย `404: Not Found` ขณะที่คำสั่ง curl โดยตรงไปยัง Bot API ทำงานได้ อาจหมายความว่า `channels.telegram.apiRoot` ถูกตั้งค่าเป็นปลายทางเต็ม `/bot` แล้ว `apiRoot` ต้องเป็นเฉพาะรากของ Bot API เท่านั้น และ `openclaw doctor --fix` จะลบ `/bot` ต่อท้ายที่เผลอใส่ไว้ - - `getMe returned 401` หมายความว่า Telegram ปฏิเสธโทเค็นบอตที่กำหนดค่าไว้ อัปเดต `botToken`, `tokenFile` หรือ `TELEGRAM_BOT_TOKEN` ด้วยโทเค็น BotFather ปัจจุบัน; OpenClaw จะหยุดก่อน polling ดังนั้นจะไม่ถูกรายงานเป็นความล้มเหลวในการล้าง Webhook - - `setMyCommands failed` พร้อมข้อผิดพลาดเครือข่าย/fetch มักหมายความว่า DNS/HTTPS ขาออกไปยัง `api.telegram.org` ถูกบล็อก + - `setMyCommands failed` พร้อม `BOT_COMMANDS_TOO_MUCH` หมายความว่าเมนู Telegram ยังมีรายการเกินหลังจากตัดทอนแล้ว ให้ลดคำสั่ง plugin/skill/กำหนดเอง หรือปิดใช้งาน `channels.telegram.commands.native` + - `deleteWebhook`, `deleteMyCommands` หรือ `setMyCommands` ล้มเหลวด้วย `404: Not Found` ขณะที่คำสั่ง curl ไปยัง Bot API โดยตรงทำงานได้ อาจหมายความว่า `channels.telegram.apiRoot` ถูกตั้งเป็นปลายทาง `/bot` แบบเต็ม `apiRoot` ต้องเป็นเพียง root ของ Bot API และ `openclaw doctor --fix` จะลบ `/bot` ต่อท้ายที่เกิดขึ้นโดยไม่ตั้งใจ + - `getMe returned 401` หมายความว่า Telegram ปฏิเสธโทเค็นบอตที่กำหนดค่าไว้ อัปเดต `botToken`, `tokenFile` หรือ `TELEGRAM_BOT_TOKEN` ด้วยโทเค็น BotFather ปัจจุบัน OpenClaw จะหยุดก่อนเริ่ม polling ดังนั้นจะไม่ถูกรายงานเป็นความล้มเหลวในการล้าง Webhook + - `setMyCommands failed` พร้อมข้อผิดพลาด network/fetch มักหมายความว่า DNS/HTTPS ขาออกไปยัง `api.telegram.org` ถูกบล็อก - ### คำสั่งจับคู่อุปกรณ์ (plugin `device-pair`) + ### คำสั่งจับคู่อุปกรณ์ (Plugin `device-pair`) - เมื่อติดตั้ง plugin `device-pair`: + เมื่อติดตั้ง Plugin `device-pair`: - 1. `/pair` สร้างโค้ดตั้งค่า - 2. วางโค้ดในแอป iOS - 3. `/pair pending` แสดงรายการคำขอที่รอดำเนินการ (รวม role/scopes) + 1. `/pair` สร้างรหัสตั้งค่า + 2. วางรหัสในแอป iOS + 3. `/pair pending` แสดงรายการคำขอที่รอดำเนินการ (รวมถึง role/scopes) 4. อนุมัติคำขอ: - `/pair approve ` สำหรับการอนุมัติแบบระบุชัดเจน - `/pair approve` เมื่อมีคำขอที่รอดำเนินการเพียงรายการเดียว - `/pair approve latest` สำหรับรายการล่าสุด - โค้ดตั้งค่ามีโทเค็น bootstrap อายุสั้น การส่งต่อ bootstrap ในตัวจะคงโทเค็นโหนดหลักไว้ที่ `scopes: []`; โทเค็นผู้ปฏิบัติการใดๆ ที่ถูกส่งต่อจะยังถูกจำกัดอยู่ที่ `operator.approvals`, `operator.read`, `operator.talk.secrets` และ `operator.write` การตรวจสอบ scope ของ bootstrap มีคำนำหน้า role ดังนั้น allowlist ของผู้ปฏิบัติการนั้นจึงตอบสนองได้เฉพาะคำขอของผู้ปฏิบัติการเท่านั้น; role ที่ไม่ใช่ผู้ปฏิบัติการยังต้องมี scope ภายใต้คำนำหน้า role ของตนเอง + รหัสตั้งค่ามาพร้อมโทเค็น bootstrap ที่มีอายุสั้น การส่งต่อ bootstrap ในตัวจะรักษาโทเค็นโหนดหลักไว้ที่ `scopes: []`; โทเค็นผู้ปฏิบัติงานที่ถูกส่งต่อใด ๆ จะถูกจำกัดอยู่ที่ `operator.approvals`, `operator.read`, `operator.talk.secrets` และ `operator.write` การตรวจสอบขอบเขต bootstrap มีคำนำหน้าตามบทบาท ดังนั้น allowlist ของผู้ปฏิบัติงานนั้นจึงใช้ได้เฉพาะกับคำขอของผู้ปฏิบัติงานเท่านั้น บทบาทที่ไม่ใช่ผู้ปฏิบัติงานยังต้องมี scopes ใต้คำนำหน้าบทบาทของตนเอง - หากอุปกรณ์ลองใหม่ด้วยรายละเอียดการยืนยันตัวตนที่เปลี่ยนไป (เช่น role/scopes/public key) คำขอที่รอดำเนินการก่อนหน้าจะถูกแทนที่ และคำขอใหม่จะใช้ `requestId` คนละค่า เรียก `/pair pending` อีกครั้งก่อนอนุมัติ + หากอุปกรณ์ลองใหม่พร้อมรายละเอียด auth ที่เปลี่ยนไป (เช่น role/scopes/public key) คำขอที่รอดำเนินการก่อนหน้าจะถูกแทนที่ และคำขอใหม่จะใช้ `requestId` อื่น เรียกใช้ `/pair pending` อีกครั้งก่อนอนุมัติ รายละเอียดเพิ่มเติม: [การจับคู่](/th/channels/pairing#pair-via-telegram-recommended-for-ios) - กำหนดค่าขอบเขตคีย์บอร์ดอินไลน์: + กำหนดค่าขอบเขตแป้นพิมพ์อินไลน์: ```json5 { @@ -418,7 +455,7 @@ curl "https://api.telegram.org/bot/getUpdates" } ``` - การแทนที่รายบัญชี: + การเขียนทับรายบัญชี: ```json5 { @@ -444,7 +481,7 @@ curl "https://api.telegram.org/bot/getUpdates" - `all` - `allowlist` (ค่าเริ่มต้น) - `capabilities: ["inlineButtons"]` แบบเก่าจะ map เป็น `inlineButtons: "all"` + `capabilities: ["inlineButtons"]` แบบเดิมจะ map เป็น `inlineButtons: "all"` ตัวอย่าง action ของข้อความ: @@ -464,31 +501,31 @@ curl "https://api.telegram.org/bot/getUpdates" } ``` - การคลิก callback จะถูกส่งต่อไปยังเอเจนต์เป็นข้อความ: + การคลิก callback จะถูกส่งต่อไปยัง agent เป็นข้อความ: `callback_data: ` - + action ของเครื่องมือ Telegram ได้แก่: - - `sendMessage` (`to`, `content`, optional `mediaUrl`, `replyToMessageId`, `messageThreadId`) + - `sendMessage` (`to`, `content`, ตัวเลือก `mediaUrl`, `replyToMessageId`, `messageThreadId`) - `react` (`chatId`, `messageId`, `emoji`) - `deleteMessage` (`chatId`, `messageId`) - `editMessage` (`chatId`, `messageId`, `content`) - - `createForumTopic` (`chatId`, `name`, optional `iconColor`, `iconCustomEmojiId`) + - `createForumTopic` (`chatId`, `name`, ตัวเลือก `iconColor`, `iconCustomEmojiId`) - action ข้อความของช่องทางเปิดเผย alias ที่ใช้งานสะดวก (`send`, `react`, `delete`, `edit`, `sticker`, `sticker-search`, `topic-create`) + action ของข้อความช่องทางเปิดเผย alias ที่ใช้งานสะดวก (`send`, `react`, `delete`, `edit`, `sticker`, `sticker-search`, `topic-create`) - ตัวควบคุมการกั้นการใช้งาน: + การควบคุมการ gating: - `channels.telegram.actions.sendMessage` - `channels.telegram.actions.deleteMessage` - `channels.telegram.actions.reactions` - - `channels.telegram.actions.sticker` (ค่าเริ่มต้น: ปิดใช้) + - `channels.telegram.actions.sticker` (ค่าเริ่มต้น: ปิดใช้งาน) - หมายเหตุ: ปัจจุบัน `edit` และ `topic-create` เปิดใช้ตามค่าเริ่มต้น และไม่มี toggle แยกใน `channels.telegram.actions.*` - การส่งขณะรันใช้ snapshot ของ config/secrets ที่ใช้งานอยู่ (เริ่มต้น/โหลดใหม่) ดังนั้นเส้นทาง action จะไม่ทำการ resolve SecretRef แบบเฉพาะกิจใหม่ต่อการส่งแต่ละครั้ง + หมายเหตุ: `edit` และ `topic-create` เปิดใช้งานโดยค่าเริ่มต้นในปัจจุบัน และไม่มี toggle `channels.telegram.actions.*` แยกต่างหาก + การส่งใน runtime ใช้ snapshot ของ config/secrets ที่ใช้งานอยู่ (startup/reload) ดังนั้นเส้นทาง action จะไม่ทำการ resolve SecretRef ใหม่แบบเฉพาะกิจต่อการส่งแต่ละครั้ง ความหมายของการลบ reaction: [/tools/reactions](/th/tools/reactions) @@ -506,29 +543,29 @@ curl "https://api.telegram.org/bot/getUpdates" - `first` - `all` - เมื่อเปิดใช้เธรดการตอบกลับและมีข้อความหรือคำบรรยาย Telegram ต้นฉบับ OpenClaw จะใส่ข้อความคำพูดแบบเนทีฟของ Telegram โดยอัตโนมัติ Telegram จำกัดข้อความคำพูดแบบเนทีฟไว้ที่ 1024 code unit แบบ UTF-16 ดังนั้นข้อความที่ยาวกว่าจะถูกยกมาจากตอนต้น และจะย้อนกลับไปเป็นการตอบกลับแบบธรรมดาหาก Telegram ปฏิเสธคำพูดนั้น + เมื่อเปิดใช้งานเธรดการตอบกลับและมีข้อความหรือคำบรรยาย Telegram ต้นฉบับ OpenClaw จะรวมข้อความอ้างอิง Telegram เนทีฟโดยอัตโนมัติ Telegram จำกัดข้อความอ้างอิงเนทีฟไว้ที่ 1024 หน่วยรหัส UTF-16 ดังนั้นข้อความที่ยาวกว่าจะถูกอ้างอิงจากตอนต้น และย้อนกลับไปใช้การตอบกลับแบบธรรมดาหาก Telegram ปฏิเสธข้อความอ้างอิง - หมายเหตุ: `off` ปิดใช้เธรดการตอบกลับโดยนัย แท็ก `[[reply_to_*]]` แบบชัดเจนยังคงถูกใช้งาน + หมายเหตุ: `off` ปิดใช้งานเธรดการตอบกลับแบบนัย แท็ก `[[reply_to_*]]` แบบชัดเจนยังคงถูกใช้งาน ซูเปอร์กรุ๊ปแบบฟอรัม: - - คีย์เซสชันหัวข้อต่อท้ายด้วย `:topic:` - - การตอบกลับและการแสดงว่ากำลังพิมพ์จะมุ่งไปยังเธรดหัวข้อ + - คีย์เซสชันของหัวข้อจะต่อท้ายด้วย `:topic:` + - การตอบกลับและการแสดงสถานะกำลังพิมพ์จะกำหนดเป้าหมายไปยังเธรดหัวข้อ - เส้นทาง config ของหัวข้อ: `channels.telegram.groups..topics.` กรณีพิเศษของหัวข้อทั่วไป (`threadId=1`): - - การส่งข้อความละเว้น `message_thread_id` (Telegram ปฏิเสธ `sendMessage(...thread_id=1)`) - - action การพิมพ์ยังใส่ `message_thread_id` + - การส่งข้อความจะละเว้น `message_thread_id` (Telegram ปฏิเสธ `sendMessage(...thread_id=1)`) + - action การแสดงสถานะกำลังพิมพ์ยังคงรวม `message_thread_id` - การสืบทอดของหัวข้อ: รายการหัวข้อจะสืบทอดการตั้งค่ากลุ่ม เว้นแต่ถูกแทนที่ (`requireMention`, `allowFrom`, `skills`, `systemPrompt`, `enabled`, `groupPolicy`) - `agentId` ใช้เฉพาะหัวข้อและไม่สืบทอดจากค่าเริ่มต้นของกลุ่ม + การสืบทอดของหัวข้อ: รายการหัวข้อจะสืบทอดการตั้งค่ากลุ่ม เว้นแต่จะถูกเขียนทับ (`requireMention`, `allowFrom`, `skills`, `systemPrompt`, `enabled`, `groupPolicy`) + `agentId` ใช้เฉพาะหัวข้อเท่านั้นและไม่สืบทอดจากค่าเริ่มต้นของกลุ่ม - **การกำหนดเส้นทางเอเจนต์รายหัวข้อ**: แต่ละหัวข้อสามารถกำหนดเส้นทางไปยังเอเจนต์คนละตัวได้โดยตั้งค่า `agentId` ใน config ของหัวข้อ วิธีนี้ทำให้แต่ละหัวข้อมี workspace, memory และเซสชันที่แยกเป็นของตัวเอง ตัวอย่าง: + **การกำหนดเส้นทาง agent รายหัวข้อ**: แต่ละหัวข้อสามารถกำหนดเส้นทางไปยัง agent คนละตัวได้โดยตั้งค่า `agentId` ใน config ของหัวข้อ วิธีนี้ทำให้แต่ละหัวข้อมี workspace, memory และ session ที่แยกเป็นของตนเอง ตัวอย่าง: ```json5 { @@ -548,28 +585,28 @@ curl "https://api.telegram.org/bot/getUpdates" } ``` - จากนั้นแต่ละหัวข้อจะมีคีย์เซสชันของตัวเอง: `agent:zu:telegram:group:-1001234567890:topic:3` + จากนั้นแต่ละหัวข้อจะมีคีย์เซสชันของตนเอง: `agent:zu:telegram:group:-1001234567890:topic:3` - **การผูกหัวข้อ ACP แบบคงอยู่**: หัวข้อฟอรัมสามารถ pin เซสชัน harness ของ ACP ผ่านการผูก ACP แบบมีชนิดที่ระดับบนสุด (`bindings[]` พร้อม `type: "acp"` และ `match.channel: "telegram"`, `peer.kind: "group"` และ ID ที่ระบุหัวข้อ เช่น `-1001234567890:topic:42`) ปัจจุบันจำกัดขอบเขตไว้ที่หัวข้อฟอรัมในกลุ่ม/ซูเปอร์กรุ๊ป ดู [เอเจนต์ ACP](/th/tools/acp-agents) + **การผูกหัวข้อ ACP แบบถาวร**: หัวข้อฟอรัมสามารถ pin เซสชัน harness ของ ACP ผ่านการผูก ACP แบบมีชนิดระดับบนสุด (`bindings[]` พร้อม `type: "acp"` และ `match.channel: "telegram"`, `peer.kind: "group"` และ id ที่ระบุหัวข้อ เช่น `-1001234567890:topic:42`) ปัจจุบันจำกัดขอบเขตไว้ที่หัวข้อฟอรัมในกลุ่ม/ซูเปอร์กรุ๊ป ดู [ACP Agents](/th/tools/acp-agents) - **การ spawn ACP ที่ผูกกับเธรดจากแชต**: `/acp spawn --thread here|auto` ผูกหัวข้อปัจจุบันกับเซสชัน ACP ใหม่; ข้อความต่อๆ ไปจะถูกกำหนดเส้นทางไปที่นั่นโดยตรง OpenClaw จะ pin การยืนยันการ spawn ในหัวข้อ ต้องให้ `channels.telegram.threadBindings.spawnSessions` เปิดใช้อยู่ (ค่าเริ่มต้น: `true`) + **การ spawn ACP ที่ผูกกับเธรดจากแชต**: `/acp spawn --thread here|auto` ผูกหัวข้อปัจจุบันกับเซสชัน ACP ใหม่ การติดตามผลจะถูกกำหนดเส้นทางไปที่นั่นโดยตรง OpenClaw จะ pin การยืนยันการ spawn ไว้ในหัวข้อ ต้องให้ `channels.telegram.threadBindings.spawnSessions` ยังคงเปิดใช้งานอยู่ (ค่าเริ่มต้น: `true`) - บริบทเทมเพลตเปิดเผย `MessageThreadId` และ `IsForum` แชต DM ที่มี `message_thread_id` จะคงการกำหนดเส้นทาง DM และเมทาดาทาการตอบกลับไว้บนเซสชันแบบ flat ตามค่าเริ่มต้น; จะใช้คีย์เซสชันที่รับรู้เธรดก็ต่อเมื่อกำหนดค่าด้วย `threadReplies: "inbound"`, `threadReplies: "always"`, `requireTopic: true` หรือ config หัวข้อที่ตรงกัน ใช้ `channels.telegram.dm.threadReplies` ระดับบนสุดสำหรับค่าเริ่มต้นของบัญชี หรือ `direct..threadReplies` สำหรับ DM หนึ่งรายการ + บริบทเทมเพลตเปิดเผย `MessageThreadId` และ `IsForum` แชต DM ที่มี `message_thread_id` จะคงการกำหนดเส้นทาง DM และเมทาดาทาการตอบกลับในเซสชันแบบแบนตามค่าเริ่มต้น โดยจะใช้คีย์เซสชันที่รับรู้เธรดก็ต่อเมื่อกำหนดค่า `threadReplies: "inbound"`, `threadReplies: "always"`, `requireTopic: true` หรือการกำหนดค่าหัวข้อที่ตรงกัน ใช้ `channels.telegram.dm.threadReplies` ระดับบนสุดสำหรับค่าเริ่มต้นของบัญชี หรือ `direct..threadReplies` สำหรับ DM หนึ่งรายการ ### ข้อความเสียง - Telegram แยกความแตกต่างระหว่างบันทึกเสียงกับไฟล์เสียง + Telegram แยกความแตกต่างระหว่างข้อความเสียงกับไฟล์เสียง - ค่าเริ่มต้น: พฤติกรรมไฟล์เสียง - - แท็ก `[[audio_as_voice]]` ในการตอบกลับของเอเจนต์เพื่อบังคับส่งเป็นบันทึกเสียง - - ทรานสคริปต์บันทึกเสียงขาเข้าจะถูกจัดกรอบเป็นข้อความที่เครื่องสร้างขึ้น - และไม่น่าเชื่อถือในบริบทของเอเจนต์; การตรวจจับการกล่าวถึงยังคงใช้ทรานสคริปต์ - ดิบ ดังนั้นข้อความเสียงที่ถูกกั้นด้วยการกล่าวถึงจึงยังทำงานต่อไปได้ + - แท็ก `[[audio_as_voice]]` ในคำตอบของเอเจนต์เพื่อบังคับส่งเป็นข้อความเสียง + - ทรานสคริปต์ข้อความเสียงขาเข้าจะถูกจัดกรอบเป็นข้อความที่สร้างโดยเครื่อง + และไม่น่าเชื่อถือในบริบทของเอเจนต์ การตรวจจับการกล่าวถึงยังคงใช้ + ทรานสคริปต์ดิบ เพื่อให้ข้อความเสียงที่ผ่านเกตการกล่าวถึงยังทำงานต่อไป - ตัวอย่าง action ของข้อความ: + ตัวอย่างการทำงานกับข้อความ: ```json5 { @@ -583,9 +620,9 @@ curl "https://api.telegram.org/bot/getUpdates" ### ข้อความวิดีโอ - Telegram แยกความแตกต่างระหว่างไฟล์วิดีโอกับวิดีโอโน้ต + Telegram แยกความแตกต่างระหว่างไฟล์วิดีโอกับข้อความวิดีโอ - ตัวอย่าง action ของข้อความ: + ตัวอย่างการทำงานกับข้อความ: ```json5 { @@ -597,17 +634,17 @@ curl "https://api.telegram.org/bot/getUpdates" } ``` - วิดีโอโน้ตไม่รองรับคำบรรยายภาพ ข้อความที่ให้มาจะถูกส่งแยกต่างหาก + ข้อความวิดีโอไม่รองรับคำบรรยาย ข้อความที่ระบุจะถูกส่งแยกต่างหาก ### สติกเกอร์ การจัดการสติกเกอร์ขาเข้า: - - WEBP แบบคงที่: ดาวน์โหลดและประมวลผลแล้ว (placeholder ``) + - WEBP แบบคงที่: ดาวน์โหลดและประมวลผลแล้ว (ตัวยึดตำแหน่ง ``) - TGS แบบเคลื่อนไหว: ข้าม - - WEBM แบบวิดีโอ: ข้าม + - WEBM วิดีโอ: ข้าม - ฟิลด์บริบทของสติกเกอร์: + ฟิลด์บริบทสติกเกอร์: - `Sticker.emoji` - `Sticker.setName` @@ -619,9 +656,9 @@ curl "https://api.telegram.org/bot/getUpdates" - `~/.openclaw/telegram/sticker-cache.json` - สติกเกอร์จะถูกอธิบายหนึ่งครั้ง (เมื่อทำได้) และถูกแคชไว้เพื่อลดการเรียก vision ซ้ำ + สติกเกอร์จะถูกอธิบายหนึ่งครั้ง (เมื่อเป็นไปได้) และแคชไว้เพื่อลดการเรียกใช้วิชันซ้ำ - เปิดใช้ action สำหรับสติกเกอร์: + เปิดใช้งานการทำงานกับสติกเกอร์: ```json5 { @@ -635,7 +672,7 @@ curl "https://api.telegram.org/bot/getUpdates" } ``` - action สำหรับส่งสติกเกอร์: + การทำงานส่งสติกเกอร์: ```json5 { @@ -659,54 +696,54 @@ curl "https://api.telegram.org/bot/getUpdates" - - Reaction ของ Telegram จะมาถึงเป็นการอัปเดต `message_reaction` (แยกจาก payload ของข้อความ) + + รีแอ็กชัน Telegram จะเข้ามาเป็นอัปเดต `message_reaction` (แยกจากเพย์โหลดข้อความ) - เมื่อเปิดใช้ OpenClaw จะจัดคิวเหตุการณ์ระบบ เช่น: + เมื่อเปิดใช้งาน OpenClaw จะจัดคิวเหตุการณ์ระบบ เช่น: - `Telegram reaction added: 👍 by Alice (@alice) on msg 42` - Config: + การกำหนดค่า: - `channels.telegram.reactionNotifications`: `off | own | all` (ค่าเริ่มต้น: `own`) - `channels.telegram.reactionLevel`: `off | ack | minimal | extensive` (ค่าเริ่มต้น: `minimal`) หมายเหตุ: - - `own` หมายถึง reaction ของผู้ใช้ต่อข้อความที่บอตส่งเท่านั้น (แบบ best-effort ผ่านแคชข้อความที่ส่งแล้ว) - - เหตุการณ์ reaction ยังคงเคารพการควบคุมสิทธิ์เข้าถึงของ Telegram (`dmPolicy`, `allowFrom`, `groupPolicy`, `groupAllowFrom`); ผู้ส่งที่ไม่ได้รับอนุญาตจะถูกทิ้ง - - Telegram ไม่ให้ thread ID ในการอัปเดต reaction - - กลุ่มที่ไม่ใช่ forum จะ route ไปยัง session แชตกลุ่ม - - กลุ่ม forum จะ route ไปยัง session หัวข้อทั่วไปของกลุ่ม (`:topic:1`) ไม่ใช่หัวข้อต้นทางที่แน่นอน + - `own` หมายถึงรีแอ็กชันของผู้ใช้ต่อข้อความที่บอตส่งเท่านั้น (ทำแบบ best-effort ผ่านแคชข้อความที่ส่งแล้ว) + - เหตุการณ์รีแอ็กชันยังคงเคารพการควบคุมการเข้าถึงของ Telegram (`dmPolicy`, `allowFrom`, `groupPolicy`, `groupAllowFrom`) ผู้ส่งที่ไม่ได้รับอนุญาตจะถูกตัดทิ้ง + - Telegram ไม่ให้ ID เธรดในอัปเดตรีแอ็กชัน + - กลุ่มที่ไม่ใช่ฟอรัมจะกำหนดเส้นทางไปยังเซสชันแชตกลุ่ม + - กลุ่มฟอรัมจะกำหนดเส้นทางไปยังเซสชันหัวข้อทั่วไปของกลุ่ม (`:topic:1`) ไม่ใช่หัวข้อต้นทางที่แน่นอน - `allowed_updates` สำหรับ polling/webhook จะรวม `message_reaction` โดยอัตโนมัติ + `allowed_updates` สำหรับ polling/Webhook จะรวม `message_reaction` โดยอัตโนมัติ - - `ackReaction` ส่งอีโมจิรับทราบขณะที่ OpenClaw กำลังประมวลผลข้อความขาเข้า + + `ackReaction` ส่งอีโมจิยืนยันระหว่างที่ OpenClaw กำลังประมวลผลข้อความขาเข้า - ลำดับการ resolve: + ลำดับการแก้ค่า: - `channels.telegram.accounts..ackReaction` - `channels.telegram.ackReaction` - `messages.ackReaction` - - fallback เป็นอีโมจิ identity ของเอเจนต์ (`agents.list[].identity.emoji` มิฉะนั้นใช้ "👀") + - ค่า fallback อีโมจิของตัวตนเอเจนต์ (`agents.list[].identity.emoji` หากไม่มีให้ใช้ "👀") หมายเหตุ: - - Telegram คาดหวังอีโมจิ Unicode (เช่น "👀") - - ใช้ `""` เพื่อปิดใช้งาน reaction สำหรับ channel หรือบัญชี + - Telegram คาดหวังอีโมจิ unicode (เช่น "👀") + - ใช้ `""` เพื่อปิดใช้งานรีแอ็กชันสำหรับช่องทางหรือบัญชี - - การเขียน config ของ channel เปิดใช้โดยค่าเริ่มต้น (`configWrites !== false`) + + การเขียนการกำหนดค่าช่องทางเปิดใช้งานตามค่าเริ่มต้น (`configWrites !== false`) - การเขียนที่ถูก trigger จาก Telegram ได้แก่: + การเขียนที่ทริกเกอร์โดย Telegram รวมถึง: - - เหตุการณ์การย้ายกลุ่ม (`migrate_to_chat_id`) เพื่ออัปเดต `channels.telegram.groups` - - `/config set` และ `/config unset` (ต้องเปิดใช้คำสั่ง) + - เหตุการณ์ย้ายกลุ่ม (`migrate_to_chat_id`) เพื่ออัปเดต `channels.telegram.groups` + - `/config set` และ `/config unset` (ต้องเปิดใช้งานคำสั่ง) ปิดใช้งาน: @@ -722,39 +759,39 @@ curl "https://api.telegram.org/bot/getUpdates" - - ค่าเริ่มต้นคือ long polling สำหรับโหมด webhook ให้ตั้งค่า `channels.telegram.webhookUrl` และ `channels.telegram.webhookSecret`; ตัวเลือกเพิ่มเติมคือ `webhookPath`, `webhookHost`, `webhookPort` (ค่าเริ่มต้น `/telegram-webhook`, `127.0.0.1`, `8787`) + + ค่าเริ่มต้นคือ long polling สำหรับโหมด Webhook ให้ตั้งค่า `channels.telegram.webhookUrl` และ `channels.telegram.webhookSecret` ตัวเลือกเสริมคือ `webhookPath`, `webhookHost`, `webhookPort` (ค่าเริ่มต้น `/telegram-webhook`, `127.0.0.1`, `8787`) - listener ในเครื่อง bind กับ `127.0.0.1:8787` สำหรับ public ingress ให้ใส่ reverse proxy ไว้หน้าพอร์ตในเครื่อง หรือตั้งค่า `webhookHost: "0.0.0.0"` อย่างตั้งใจ + ตัวรับฟังภายในเครื่องผูกกับ `127.0.0.1:8787` สำหรับทางเข้าสาธารณะ ให้ตั้ง reverse proxy ไว้หน้าพอร์ตภายในเครื่อง หรือตั้งค่า `webhookHost: "0.0.0.0"` โดยตั้งใจ - โหมด Webhook จะตรวจสอบ request guard, secret token ของ Telegram และ body JSON ก่อนส่งคืน `200` ให้ Telegram - จากนั้น OpenClaw จะประมวลผลการอัปเดตแบบ asynchronous ผ่าน bot lane ต่อแชต/ต่อหัวข้อเดียวกับที่ long polling ใช้ ดังนั้น agent turn ที่ช้าจะไม่ทำให้ ACK การส่งของ Telegram ค้างอยู่ + โหมด Webhook ตรวจสอบ request guards, โทเค็นลับของ Telegram และเนื้อหา JSON ก่อนส่งคืน `200` ให้ Telegram + จากนั้น OpenClaw จะประมวลผลอัปเดตแบบอะซิงโครนัสผ่านเลนบอตต่อแชต/ต่อหัวข้อเดียวกับที่ใช้โดย long polling ดังนั้นรอบการทำงานของเอเจนต์ที่ช้าจะไม่ยึด ACK การส่งมอบของ Telegram ไว้ - + - ค่าเริ่มต้นของ `channels.telegram.textChunkLimit` คือ 4000 - `channels.telegram.chunkMode="newline"` จะให้ความสำคัญกับขอบเขตย่อหน้า (บรรทัดว่าง) ก่อนแยกตามความยาว - - `channels.telegram.mediaMaxMb` (ค่าเริ่มต้น 100) จำกัดขนาดสื่อ Telegram ขาเข้าและขาออก - - `channels.telegram.mediaGroupFlushMs` (ค่าเริ่มต้น 500) ควบคุมระยะเวลาที่อัลบั้ม/กลุ่มสื่อของ Telegram จะถูก buffer ก่อนที่ OpenClaw จะ dispatch เป็นข้อความขาเข้าหนึ่งข้อความ เพิ่มค่านี้หากส่วนต่าง ๆ ของอัลบั้มมาถึงช้า ลดค่านี้เพื่อลด latency ของการตอบกลับอัลบั้ม - - `channels.telegram.timeoutSeconds` override timeout ของไคลเอนต์ Telegram API (หากไม่ได้ตั้งค่า จะใช้ค่าเริ่มต้นของ grammY) ไคลเอนต์บอตจะ clamp ค่าที่ config ไว้ซึ่งต่ำกว่า guard 60 วินาทีสำหรับ request ข้อความ/typing ขาออก เพื่อให้ grammY ไม่ abort การส่ง reply ที่มองเห็นได้ก่อนที่ transport guard และ fallback ของ OpenClaw จะทำงาน Long polling ยังคงใช้ guard 45 วินาทีสำหรับ request `getUpdates` เพื่อไม่ให้ idle poll ถูกปล่อยทิ้งไว้อย่างไม่มีกำหนด - - ค่าเริ่มต้นของ `channels.telegram.pollingStallThresholdMs` คือ `120000`; ปรับระหว่าง `30000` ถึง `600000` เฉพาะสำหรับการ restart จาก polling-stall แบบ false positive - - ประวัติบริบทกลุ่มใช้ `channels.telegram.historyLimit` หรือ `messages.groupChat.historyLimit` (ค่าเริ่มต้น 50); `0` คือปิดใช้งาน - - บริบทเสริมของ reply/quote/forward ปัจจุบันจะถูกส่งต่อตามที่ได้รับ - - allowlist ของ Telegram หลัก ๆ ใช้ gate ว่าใคร trigger เอเจนต์ได้ ไม่ใช่ขอบเขตการลบข้อมูลบริบทเสริมแบบเต็ม - - ตัวควบคุมประวัติ DM: + - `channels.telegram.mediaMaxMb` (ค่าเริ่มต้น 100) จำกัดขนาดสื่อ Telegram ทั้งขาเข้าและขาออก + - `channels.telegram.mediaGroupFlushMs` (ค่าเริ่มต้น 500) ควบคุมระยะเวลาที่อัลบั้ม/กลุ่มสื่อของ Telegram จะถูกบัฟเฟอร์ก่อน OpenClaw ส่งต่อเป็นข้อความขาเข้าหนึ่งรายการ เพิ่มค่านี้หากส่วนของอัลบั้มมาถึงช้า ลดค่านี้เพื่อลดเวลาแฝงของการตอบอัลบั้ม + - `channels.telegram.timeoutSeconds` เขียนทับ timeout ของไคลเอนต์ Telegram API (หากไม่ได้ตั้งค่า จะใช้ค่าเริ่มต้นของ grammY) ไคลเอนต์บอตจะ clamp ค่าที่กำหนดไว้ต่ำกว่า request guard ข้อความ/การพิมพ์ขาออก 60 วินาที เพื่อไม่ให้ grammY ยกเลิกการส่งคำตอบที่มองเห็นได้ก่อนที่ transport guard และ fallback ของ OpenClaw จะทำงานได้ Long polling ยังคงใช้ request guard `getUpdates` 45 วินาที เพื่อไม่ให้ polling ที่ไม่มีงานถูกทิ้งไว้ไม่มีกำหนด + - ค่าเริ่มต้นของ `channels.telegram.pollingStallThresholdMs` คือ `120000` ปรับระหว่าง `30000` ถึง `600000` เฉพาะสำหรับการรีสตาร์ตจาก polling-stall ที่เป็น false-positive + - ประวัติบริบทกลุ่มใช้ `channels.telegram.historyLimit` หรือ `messages.groupChat.historyLimit` (ค่าเริ่มต้น 50) `0` จะปิดใช้งาน + - บริบทเสริมจากการตอบกลับ/การอ้างอิง/การส่งต่อจะถูกส่งผ่านตามที่ได้รับในปัจจุบัน + - allowlists ของ Telegram มีไว้หลัก ๆ เพื่อควบคุมว่าใครสามารถทริกเกอร์เอเจนต์ได้ ไม่ใช่ขอบเขตการปกปิดบริบทเสริมอย่างเต็มรูปแบบ + - การควบคุมประวัติ DM: - `channels.telegram.dmHistoryLimit` - `channels.telegram.dms[""].historyLimit` - - config `channels.telegram.retry` ใช้กับ helper ส่ง Telegram (CLI/tools/actions) สำหรับข้อผิดพลาด API ขาออกที่กู้คืนได้ การส่ง final-reply ขาเข้าก็ใช้ safe-send retry แบบมีขอบเขตสำหรับความล้มเหลว pre-connect ของ Telegram เช่นกัน แต่จะไม่ retry envelope เครือข่ายหลังส่งที่กำกวมซึ่งอาจทำให้ข้อความที่มองเห็นได้ซ้ำกัน + - การกำหนดค่า `channels.telegram.retry` ใช้กับตัวช่วยส่ง Telegram (CLI/เครื่องมือ/actions) สำหรับข้อผิดพลาด API ขาออกที่กู้คืนได้ การส่งคำตอบสุดท้ายขาเข้ายังใช้การลองซ้ำ safe-send แบบมีขอบเขตสำหรับความล้มเหลวก่อนเชื่อมต่อของ Telegram แต่จะไม่ลองซ้ำ network envelopes หลังการส่งที่กำกวมซึ่งอาจทำให้ข้อความที่มองเห็นได้ซ้ำกัน - เป้าหมายการส่งของ CLI เป็น numeric chat ID หรือ username ได้: + เป้าหมายส่งของ CLI อาจเป็น chat ID แบบตัวเลขหรือชื่อผู้ใช้: ```bash openclaw message send --channel telegram --target 123456789 --message "hi" openclaw message send --channel telegram --target @name --message "hi" ``` - poll ของ Telegram ใช้ `openclaw message poll` และรองรับหัวข้อ forum: + polls ของ Telegram ใช้ `openclaw message poll` และรองรับหัวข้อฟอรัม: ```bash openclaw message poll --channel telegram --target 123456789 \ @@ -764,57 +801,57 @@ openclaw message poll --channel telegram --target -1001234567890:topic:42 \ --poll-duration-seconds 300 --poll-public ``` - flag สำหรับ poll เฉพาะ Telegram: + flag poll เฉพาะ Telegram: - `--poll-duration-seconds` (5-600) - `--poll-anonymous` - `--poll-public` - - `--thread-id` สำหรับหัวข้อ forum (หรือใช้เป้าหมาย `:topic:`) + - `--thread-id` สำหรับหัวข้อฟอรัม (หรือใช้เป้าหมาย `:topic:`) - การส่งของ Telegram ยังรองรับ: + การส่ง Telegram ยังรองรับ: - - `--presentation` พร้อมบล็อก `buttons` สำหรับ inline keyboard เมื่อ `channels.telegram.capabilities.inlineButtons` อนุญาต - - `--pin` หรือ `--delivery '{"pin":true}'` เพื่อขอการส่งแบบปักหมุดเมื่อบอตปักหมุดในแชตนั้นได้ - - `--force-document` เพื่อส่งรูปภาพและ GIF ขาออกเป็นเอกสารแทนการอัปโหลดแบบภาพถ่ายที่บีบอัดหรือสื่อเคลื่อนไหว + - `--presentation` พร้อมบล็อก `buttons` สำหรับ inline keyboards เมื่อ `channels.telegram.capabilities.inlineButtons` อนุญาต + - `--pin` หรือ `--delivery '{"pin":true}'` เพื่อขอการส่งแบบปักหมุดเมื่อบอตสามารถปักหมุดในแชตนั้นได้ + - `--force-document` เพื่อส่งรูปภาพและ GIF ขาออกเป็นเอกสารแทนการอัปโหลดเป็นรูปภาพที่บีบอัดหรือสื่อเคลื่อนไหว - การ gate action: + การควบคุม action: - - `channels.telegram.actions.sendMessage=false` ปิดใช้งานข้อความ Telegram ขาออก รวมถึง poll - - `channels.telegram.actions.poll=false` ปิดใช้งานการสร้าง poll ของ Telegram แต่ยังเปิดใช้การส่งปกติไว้ + - `channels.telegram.actions.sendMessage=false` ปิดใช้งานข้อความ Telegram ขาออก รวมถึง polls + - `channels.telegram.actions.poll=false` ปิดใช้งานการสร้าง poll ของ Telegram แต่ยังเปิดให้ส่งแบบปกติได้ - - Telegram รองรับการอนุมัติ exec ใน DM ของผู้อนุมัติ และสามารถโพสต์ prompt ในแชตหรือหัวข้อต้นทางได้ตามต้องการ ผู้อนุมัติต้องเป็น numeric Telegram user ID + + Telegram รองรับการอนุมัติ exec ใน DM ของผู้อนุมัติ และสามารถเลือกโพสต์ prompt ในแชตหรือหัวข้อต้นทางได้ ผู้อนุมัติต้องเป็น ID ผู้ใช้ Telegram แบบตัวเลข - path ของ config: + พาธการกำหนดค่า: - - `channels.telegram.execApprovals.enabled` (เปิดใช้โดยอัตโนมัติเมื่อ resolve ผู้อนุมัติได้อย่างน้อยหนึ่งคน) - - `channels.telegram.execApprovals.approvers` (fallback ไปยัง numeric owner ID จาก `commands.ownerAllowFrom`) + - `channels.telegram.execApprovals.enabled` (เปิดใช้งานอัตโนมัติเมื่อสามารถ resolve ผู้อนุมัติได้อย่างน้อยหนึ่งคน) + - `channels.telegram.execApprovals.approvers` (fallback ไปยัง ID เจ้าของแบบตัวเลขจาก `commands.ownerAllowFrom`) - `channels.telegram.execApprovals.target`: `dm` (ค่าเริ่มต้น) | `channel` | `both` - `agentFilter`, `sessionFilter` - `channels.telegram.allowFrom`, `groupAllowFrom` และ `defaultTo` ควบคุมว่าใครคุยกับบอตได้ และบอตส่ง reply ปกติไปที่ใด สิ่งเหล่านี้ไม่ได้ทำให้ใครเป็นผู้อนุมัติ exec การจับคู่ DM ที่ได้รับอนุมัติครั้งแรกจะ bootstrap `commands.ownerAllowFrom` เมื่อยังไม่มีเจ้าของคำสั่ง ดังนั้นการตั้งค่าเจ้าของหนึ่งคนยังทำงานได้โดยไม่ต้องใส่ ID ซ้ำใต้ `execApprovals.approvers` + `channels.telegram.allowFrom`, `groupAllowFrom` และ `defaultTo` ควบคุมว่าใครสามารถคุยกับบอตได้และจะส่งคำตอบปกติไปที่ใด แต่ไม่ได้ทำให้ใครเป็นผู้อนุมัติ exec การจับคู่ DM ที่อนุมัติครั้งแรกจะ bootstrap `commands.ownerAllowFrom` เมื่อยังไม่มีเจ้าของคำสั่ง ดังนั้นการตั้งค่าเจ้าของคนเดียวยังคงทำงานได้โดยไม่ต้องทำซ้ำ ID ใต้ `execApprovals.approvers` - การส่งไปยัง channel จะแสดงข้อความคำสั่งในแชต เปิดใช้ `channel` หรือ `both` เฉพาะในกลุ่ม/หัวข้อที่เชื่อถือได้เท่านั้น เมื่อ prompt ไปถึงหัวข้อ forum OpenClaw จะรักษาหัวข้อนั้นไว้สำหรับ prompt การอนุมัติและข้อความติดตาม การอนุมัติ exec หมดอายุหลังจาก 30 นาทีโดยค่าเริ่มต้น + การส่งไปยังช่องทางจะแสดงข้อความคำสั่งในแชต เปิดใช้งาน `channel` หรือ `both` เฉพาะในกลุ่ม/หัวข้อที่เชื่อถือได้เท่านั้น เมื่อ prompt ไปถึงหัวข้อฟอรัม OpenClaw จะรักษาหัวข้อนั้นไว้สำหรับ prompt อนุมัติและข้อความติดตามผล การอนุมัติ exec จะหมดอายุหลัง 30 นาทีตามค่าเริ่มต้น - ปุ่มอนุมัติแบบ inline ยังต้องให้ `channels.telegram.capabilities.inlineButtons` อนุญาต surface เป้าหมาย (`dm`, `group` หรือ `all`) ด้วย ID การอนุมัติที่ขึ้นต้นด้วย `plugin:` จะ resolve ผ่านการอนุมัติของ plugin ส่วน ID อื่นจะ resolve ผ่านการอนุมัติ exec ก่อน + ปุ่มอนุมัติแบบ inline ยังต้องให้ `channels.telegram.capabilities.inlineButtons` อนุญาตพื้นผิวเป้าหมาย (`dm`, `group` หรือ `all`) ด้วย ID การอนุมัติที่ขึ้นต้นด้วย `plugin:` จะ resolve ผ่านการอนุมัติของ plugin ส่วนรายการอื่นจะ resolve ผ่านการอนุมัติ exec ก่อน ดู [การอนุมัติ Exec](/th/tools/exec-approvals) -## ตัวควบคุมการตอบกลับข้อผิดพลาด +## การควบคุมคำตอบข้อผิดพลาด -เมื่อเอเจนต์พบข้อผิดพลาดการส่งหรือ provider Telegram สามารถตอบกลับด้วยข้อความข้อผิดพลาดหรือระงับไว้ได้ มี config key สองรายการที่ควบคุมพฤติกรรมนี้: +เมื่อเอเจนต์พบข้อผิดพลาดในการส่งหรือผู้ให้บริการ Telegram สามารถตอบกลับด้วยข้อความข้อผิดพลาดหรือปิดไม่ให้แสดงได้ คีย์การกำหนดค่าสองรายการควบคุมพฤติกรรมนี้: -| Key | Values | ค่าเริ่มต้น | คำอธิบาย | +| คีย์ | ค่า | ค่าเริ่มต้น | คำอธิบาย | | ----------------------------------- | ----------------- | ------- | ----------------------------------------------------------------------------------------------- | -| `channels.telegram.errorPolicy` | `reply`, `silent` | `reply` | `reply` ส่งข้อความข้อผิดพลาดที่เป็นมิตรไปยังแชต `silent` ระงับการตอบกลับข้อผิดพลาดทั้งหมด | -| `channels.telegram.errorCooldownMs` | number (ms) | `60000` | เวลาขั้นต่ำระหว่างการตอบกลับข้อผิดพลาดไปยังแชตเดียวกัน ป้องกัน spam ข้อผิดพลาดระหว่างเหตุขัดข้อง | +| `channels.telegram.errorPolicy` | `reply`, `silent` | `reply` | `reply` ส่งข้อความข้อผิดพลาดที่เป็นมิตรไปยังแชต `silent` ปิดคำตอบข้อผิดพลาดทั้งหมด | +| `channels.telegram.errorCooldownMs` | number (ms) | `60000` | เวลาขั้นต่ำระหว่างคำตอบข้อผิดพลาดไปยังแชตเดียวกัน ป้องกันสแปมข้อผิดพลาดระหว่างเหตุขัดข้อง | -รองรับ override ต่อบัญชี ต่อกลุ่ม และต่อหัวข้อ (ใช้การสืบทอดเดียวกับ config key อื่นของ Telegram) +รองรับการเขียนทับต่อบัญชี ต่อกลุ่ม และต่อหัวข้อ (ใช้การสืบทอดเดียวกับคีย์การกำหนดค่า Telegram อื่น ๆ) ```json5 { @@ -835,56 +872,56 @@ openclaw message poll --channel telegram --target -1001234567890:topic:42 \ ## การแก้ไขปัญหา - + - - หาก `requireMention=false` โหมด privacy ของ Telegram ต้องอนุญาตการมองเห็นแบบเต็ม + - หาก `requireMention=false` โหมดความเป็นส่วนตัวของ Telegram ต้องอนุญาตการมองเห็นเต็มรูปแบบ - BotFather: `/setprivacy` -> Disable - - จากนั้นลบ + เพิ่มบอตกลับเข้ากลุ่ม - - `openclaw channels status` จะเตือนเมื่อ config คาดหวังข้อความกลุ่มที่ไม่ได้ mention - - `openclaw channels status --probe` ตรวจสอบ numeric group ID ที่ระบุชัดได้ wildcard `"*"` ไม่สามารถ probe membership ได้ - - ทดสอบ session แบบเร็ว: `/activation always` + - จากนั้นลบและเพิ่มบอตกลับเข้ากลุ่มใหม่ + - `openclaw channels status` เตือนเมื่อการกำหนดค่าคาดหวังข้อความกลุ่มที่ไม่มีการกล่าวถึง + - `openclaw channels status --probe` สามารถตรวจสอบ ID กลุ่มแบบตัวเลขที่ระบุชัดเจนได้ wildcard `"*"` ไม่สามารถ membership-probed ได้ + - การทดสอบเซสชันอย่างรวดเร็ว: `/activation always` - - เมื่อมี `channels.telegram.groups` กลุ่มต้องอยู่ในรายการ (หรือรวม `"*"`) - - ตรวจสอบ membership ของบอตในกลุ่ม - - ตรวจสอบ log: `openclaw logs --follow` เพื่อดูเหตุผลที่ข้าม + - เมื่อมี `channels.telegram.groups` อยู่ ต้องระบุกลุ่มไว้ในรายการ (หรือใส่ `"*"`) + - ตรวจสอบการเป็นสมาชิกของบอตในกลุ่ม + - ตรวจสอบบันทึก: `openclaw logs --follow` เพื่อดูเหตุผลที่ข้าม - + - - อนุญาต identity ของผู้ส่งของคุณ (การจับคู่และ/หรือ numeric `allowFrom`) - - การอนุญาตคำสั่งยังคงมีผลแม้เมื่อ policy ของกลุ่มเป็น `open` - - `setMyCommands failed` พร้อม `BOT_COMMANDS_TOO_MUCH` หมายความว่าเมนู native มีรายการมากเกินไป ลดคำสั่ง plugin/skill/custom หรือปิดใช้งานเมนู native - - การเรียก startup `deleteMyCommands` / `setMyCommands` และการเรียก typing `sendChatAction` ถูกจำกัดเวลาและ retry หนึ่งครั้งผ่าน transport fallback ของ Telegram เมื่อ request timeout ข้อผิดพลาด network/fetch ที่เกิดซ้ำมักบ่งชี้ปัญหา DNS/HTTPS reachability ไปยัง `api.telegram.org` + - อนุญาตตัวตนผู้ส่งของคุณ (การจับคู่ และ/หรือ `allowFrom` แบบตัวเลข) + - การอนุญาตคำสั่งยังคงมีผล แม้นโยบายกลุ่มจะเป็น `open` + - `setMyCommands failed` พร้อม `BOT_COMMANDS_TOO_MUCH` หมายความว่าเมนูเนทีฟมีรายการมากเกินไป ให้ลดจำนวนคำสั่งจาก Plugin/Skills/คำสั่งแบบกำหนดเอง หรือปิดใช้เมนูเนทีฟ + - การเรียกตอนเริ่มต้น `deleteMyCommands` / `setMyCommands` และการเรียกสถานะกำลังพิมพ์ `sendChatAction` มีขอบเขตจำกัดและลองซ้ำหนึ่งครั้งผ่านทางสำรองการส่งข้อมูลของ Telegram เมื่อคำขอหมดเวลา ข้อผิดพลาดเครือข่าย/การดึงข้อมูลที่เกิดซ้ำมักบ่งชี้ปัญหาการเข้าถึง DNS/HTTPS ไปยัง `api.telegram.org` - + - - `getMe returned 401` คือความล้มเหลวในการยืนยันตัวตนของ Telegram สำหรับโทเค็นบอตที่กำหนดค่าไว้ - - คัดลอกใหม่หรือสร้างโทเค็นบอตใหม่ใน BotFather จากนั้นอัปเดต `channels.telegram.botToken`, `channels.telegram.tokenFile`, `channels.telegram.accounts..botToken` หรือ `TELEGRAM_BOT_TOKEN` สำหรับบัญชีเริ่มต้น - - `deleteWebhook 401 Unauthorized` ระหว่างการเริ่มต้นก็เป็นความล้มเหลวในการยืนยันตัวตนเช่นกัน การถือว่าเป็น "ไม่มี webhook อยู่" จะเพียงเลื่อนความล้มเหลวจากโทเค็นที่ผิดเดิมไปยังการเรียก API ภายหลังเท่านั้น + - `getMe returned 401` คือความล้มเหลวในการยืนยันตัวตนกับ Telegram สำหรับโทเค็นบอตที่กำหนดค่าไว้ + - คัดลอกโทเค็นบอตอีกครั้งหรือสร้างใหม่ใน BotFather แล้วอัปเดต `channels.telegram.botToken`, `channels.telegram.tokenFile`, `channels.telegram.accounts..botToken` หรือ `TELEGRAM_BOT_TOKEN` สำหรับบัญชีเริ่มต้น + - `deleteWebhook 401 Unauthorized` ระหว่างเริ่มต้นก็เป็นความล้มเหลวด้านการยืนยันตัวตนเช่นกัน การถือว่าเป็น "ไม่มี webhook อยู่" จะเพียงเลื่อนความล้มเหลวจากโทเค็นที่ไม่ถูกต้องเดิมไปยังการเรียก API ภายหลังเท่านั้น - + - - Node 22+ + fetch/proxy แบบกำหนดเองอาจทำให้เกิดพฤติกรรมยกเลิกทันทีหากชนิด AbortSignal ไม่ตรงกัน - - โฮสต์บางตัว resolve `api.telegram.org` เป็น IPv6 ก่อน egress IPv6 ที่เสียอาจทำให้ Telegram API ล้มเหลวเป็นครั้งคราว - - หาก log มี `TypeError: fetch failed` หรือ `Network request for 'getUpdates' failed!` ตอนนี้ OpenClaw จะลองใหม่โดยถือว่าเป็นข้อผิดพลาดเครือข่ายที่กู้คืนได้ - - ระหว่างการเริ่มต้น polling, OpenClaw จะใช้ probe `getMe` ตอนเริ่มต้นที่สำเร็จซ้ำสำหรับ grammY เพื่อให้ runner ไม่ต้องใช้ `getMe` ครั้งที่สองก่อน `getUpdates` ครั้งแรก - - หาก `deleteWebhook` ล้มเหลวด้วยข้อผิดพลาดเครือข่ายชั่วคราวระหว่างการเริ่มต้น polling, OpenClaw จะทำ long polling ต่อแทนการเรียก control-plane ก่อน poll อีกครั้ง หากยังมี webhook ที่ใช้งานอยู่ จะปรากฏเป็นความขัดแย้งของ `getUpdates`; จากนั้น OpenClaw จะสร้าง transport ของ Telegram ใหม่และลองล้าง webhook อีกครั้ง - - หาก socket ของ Telegram ถูกรีไซเคิลตามรอบคงที่สั้น ๆ ให้ตรวจสอบว่า `channels.telegram.timeoutSeconds` ต่ำหรือไม่; client บอตจะ clamp ค่าที่กำหนดไว้ให้ไม่ต่ำกว่า guard ของคำขอ outbound และ `getUpdates` แต่ release เก่าอาจยกเลิกทุก poll หรือ reply เมื่อค่านี้ถูกตั้งต่ำกว่า guard เหล่านั้น - - หาก log มี `Polling stall detected` โดยค่าเริ่มต้น OpenClaw จะเริ่ม polling ใหม่และสร้าง transport ของ Telegram ใหม่หลังจาก 120 วินาทีโดยไม่มี liveness ของ long-poll ที่เสร็จสมบูรณ์ - - `openclaw channels status --probe` และ `openclaw doctor` จะเตือนเมื่อบัญชี polling ที่กำลังทำงานยังทำ `getUpdates` ไม่เสร็จหลังช่วงผ่อนผันการเริ่มต้น เมื่อบัญชี webhook ที่กำลังทำงานยังทำ `setWebhook` ไม่เสร็จหลังช่วงผ่อนผันการเริ่มต้น หรือเมื่อกิจกรรม transport ของ polling ที่สำเร็จครั้งล่าสุดเก่าเกินไป - - เพิ่ม `channels.telegram.pollingStallThresholdMs` เฉพาะเมื่อการเรียก `getUpdates` ที่ทำงานนานยังปกติ แต่โฮสต์ของคุณยังรายงานการรีสตาร์ทจาก polling-stall ผิดพลาดอยู่ การ stall ต่อเนื่องมักชี้ไปที่ปัญหา proxy, DNS, IPv6 หรือ TLS egress ระหว่างโฮสต์กับ `api.telegram.org` - - Telegram ยังเคารพ env proxy ของ process สำหรับ transport ของ Bot API รวมถึง `HTTP_PROXY`, `HTTPS_PROXY`, `ALL_PROXY` และตัวแปรตัวพิมพ์เล็กของรายการเหล่านี้ `NO_PROXY` / `no_proxy` ยังสามารถ bypass `api.telegram.org` ได้ - - หากกำหนดค่า proxy ที่ OpenClaw จัดการผ่าน `OPENCLAW_PROXY_URL` สำหรับสภาพแวดล้อมบริการ และไม่มี env proxy มาตรฐานอยู่ Telegram จะใช้ URL นั้นสำหรับ transport ของ Bot API ด้วย - - บนโฮสต์ VPS ที่มี egress/TLS โดยตรงไม่เสถียร ให้ route การเรียก Telegram API ผ่าน `channels.telegram.proxy`: + - Node 22+ พร้อม fetch/proxy แบบกำหนดเองอาจทำให้เกิดพฤติกรรมยกเลิกทันทีหากชนิด AbortSignal ไม่ตรงกัน + - บางโฮสต์ resolve `api.telegram.org` เป็น IPv6 ก่อน การออก IPv6 ที่เสียอาจทำให้ Telegram API ล้มเหลวเป็นพัก ๆ + - หากบันทึกมี `TypeError: fetch failed` หรือ `Network request for 'getUpdates' failed!` ตอนนี้ OpenClaw จะลองซ้ำข้อผิดพลาดเหล่านี้ในฐานะข้อผิดพลาดเครือข่ายที่กู้คืนได้ + - ระหว่างการเริ่มต้น polling OpenClaw จะนำการตรวจสอบ `getMe` ตอนเริ่มต้นที่สำเร็จกลับมาใช้กับ grammY เพื่อให้ runner ไม่ต้องใช้ `getMe` ครั้งที่สองก่อน `getUpdates` ครั้งแรก + - หาก `deleteWebhook` ล้มเหลวด้วยข้อผิดพลาดเครือข่ายชั่วคราวระหว่างเริ่มต้น polling OpenClaw จะเข้าสู่ long polling ต่อไปแทนการเรียก control-plane ก่อน poll อีกครั้ง Webhook ที่ยังเปิดใช้งานอยู่จะปรากฏเป็นข้อขัดแย้งของ `getUpdates` จากนั้น OpenClaw จะสร้างการส่งข้อมูล Telegram ใหม่และลองล้าง webhook อีกครั้ง + - หากซ็อกเก็ต Telegram ถูกรีไซเคิลตามรอบคงที่สั้น ๆ ให้ตรวจสอบว่า `channels.telegram.timeoutSeconds` ต่ำหรือไม่ ไคลเอนต์บอตจะ clamp ค่าที่กำหนดไว้ต่ำกว่า guard ของคำขอขาออกและ `getUpdates` แต่รุ่นเก่ากว่าอาจยกเลิกทุก poll หรือทุกการตอบกลับเมื่อค่านี้ถูกตั้งต่ำกว่า guard เหล่านั้น + - หากบันทึกมี `Polling stall detected` OpenClaw จะรีสตาร์ต polling และสร้างการส่งข้อมูล Telegram ใหม่หลังจากไม่มี liveness ของ long-poll ที่เสร็จสมบูรณ์เป็นเวลา 120 วินาทีตามค่าเริ่มต้น + - `openclaw channels status --probe` และ `openclaw doctor` จะเตือนเมื่อบัญชี polling ที่กำลังทำงานยังไม่เสร็จสิ้น `getUpdates` หลังช่วงผ่อนผันการเริ่มต้น เมื่อบัญชี webhook ที่กำลังทำงานยังไม่เสร็จสิ้น `setWebhook` หลังช่วงผ่อนผันการเริ่มต้น หรือเมื่อกิจกรรมการส่งข้อมูล polling ที่สำเร็จล่าสุดเก่าเกินไป + - เพิ่ม `channels.telegram.pollingStallThresholdMs` เฉพาะเมื่อการเรียก `getUpdates` ที่ทำงานนานยังปกติ แต่โฮสต์ของคุณยังรายงานการรีสตาร์ตจาก polling-stall ผิดพลาด การค้างที่เกิดซ้ำมักชี้ไปที่ปัญหา proxy, DNS, IPv6 หรือ TLS egress ระหว่างโฮสต์กับ `api.telegram.org` + - Telegram ยังเคารพ env proxy ของ process สำหรับการส่งข้อมูล Bot API รวมถึง `HTTP_PROXY`, `HTTPS_PROXY`, `ALL_PROXY` และตัวแปรพิมพ์เล็กของค่าเหล่านั้น `NO_PROXY` / `no_proxy` ยังสามารถข้าม `api.telegram.org` ได้ + - หากกำหนดค่า proxy ที่ OpenClaw จัดการผ่าน `OPENCLAW_PROXY_URL` สำหรับสภาพแวดล้อมบริการและไม่มี env proxy มาตรฐาน Telegram จะใช้ URL นั้นสำหรับการส่งข้อมูล Bot API ด้วย + - บนโฮสต์ VPS ที่มี direct egress/TLS ไม่เสถียร ให้ส่งการเรียก Telegram API ผ่าน `channels.telegram.proxy`: ```yaml channels: @@ -892,8 +929,8 @@ channels: proxy: socks5://:@proxy-host:1080 ``` - - Node 22+ มีค่าเริ่มต้นเป็น `autoSelectFamily=true` (ยกเว้น WSL2) ลำดับผลลัพธ์ DNS ของ Telegram จะเคารพ `OPENCLAW_TELEGRAM_DNS_RESULT_ORDER` ก่อน จากนั้น `channels.telegram.network.dnsResultOrder` แล้วจึงเป็นค่าเริ่มต้นของ process เช่น `NODE_OPTIONS=--dns-result-order=ipv4first`; หากไม่มีรายการใดใช้ได้ Node 22+ จะ fallback เป็น `ipv4first` - - หากโฮสต์ของคุณเป็น WSL2 หรือทำงานได้ดีกว่าอย่างชัดเจนด้วยพฤติกรรม IPv4-only ให้บังคับการเลือก family: + - Node 22+ ตั้งค่าเริ่มต้นเป็น `autoSelectFamily=true` (ยกเว้น WSL2) ลำดับผลลัพธ์ DNS ของ Telegram จะเคารพ `OPENCLAW_TELEGRAM_DNS_RESULT_ORDER` จากนั้น `channels.telegram.network.dnsResultOrder` จากนั้นค่าเริ่มต้นของ process เช่น `NODE_OPTIONS=--dns-result-order=ipv4first`; หากไม่มีค่าใดใช้ได้ Node 22+ จะ fallback เป็น `ipv4first` + - หากโฮสต์ของคุณเป็น WSL2 หรือทำงานได้ดีกว่าอย่างชัดเจนเมื่อใช้พฤติกรรม IPv4 เท่านั้น ให้บังคับการเลือก family: ```yaml channels: @@ -902,11 +939,11 @@ channels: autoSelectFamily: false ``` - - คำตอบช่วง benchmark ของ RFC 2544 (`198.18.0.0/15`) ได้รับอนุญาต - สำหรับการดาวน์โหลดสื่อ Telegram ตามค่าเริ่มต้นอยู่แล้ว หาก fake-IP ที่เชื่อถือได้หรือ + - คำตอบช่วง benchmark ของ RFC 2544 (`198.18.0.0/15`) ได้รับอนุญาตอยู่แล้ว + สำหรับการดาวน์โหลดสื่อ Telegram ตามค่าเริ่มต้น หาก fake-IP ที่เชื่อถือได้หรือ proxy แบบโปร่งใสเขียน `api.telegram.org` ใหม่เป็นที่อยู่ - private/internal/special-use อื่นระหว่างการดาวน์โหลดสื่อ คุณสามารถ opt - in เข้า bypass เฉพาะ Telegram ได้: + private/internal/special-use อื่นระหว่างการดาวน์โหลดสื่อ คุณสามารถเลือกเปิด + การ bypass เฉพาะ Telegram ได้: ```yaml channels: @@ -915,18 +952,18 @@ channels: dangerouslyAllowPrivateNetwork: true ``` - - opt-in เดียวกันนี้ใช้ได้ต่อบัญชีที่ + - การเลือกเปิดแบบเดียวกันใช้ได้ต่อบัญชีที่ `channels.telegram.accounts..network.dangerouslyAllowPrivateNetwork` - หาก proxy ของคุณ resolve โฮสต์สื่อ Telegram เป็น `198.18.x.x` ให้ปิด - flag อันตรายไว้ก่อน สื่อ Telegram อนุญาตช่วง benchmark RFC 2544 + flag อันตรายไว้ก่อน สื่อ Telegram อนุญาตช่วง benchmark ของ RFC 2544 ตามค่าเริ่มต้นอยู่แล้ว `channels.telegram.network.dangerouslyAllowPrivateNetwork` ทำให้การป้องกัน - SSRF ของสื่อ Telegram อ่อนลง ใช้เฉพาะกับสภาพแวดล้อม proxy ที่ผู้ปฏิบัติการควบคุมและเชื่อถือได้ - เช่น Clash, Mihomo หรือ Surge fake-IP routing เมื่อระบบเหล่านั้น - สร้างคำตอบ private หรือ special-use นอกช่วง benchmark RFC 2544 - ปล่อยให้ปิดไว้สำหรับการเข้าถึง Telegram ผ่านอินเทอร์เน็ตสาธารณะตามปกติ + SSRF ของสื่อ Telegram อ่อนลง ใช้เฉพาะกับสภาพแวดล้อม proxy ที่เชื่อถือได้และควบคุมโดยผู้ปฏิบัติงาน + เช่นการกำหนดเส้นทาง fake-IP ของ Clash, Mihomo หรือ Surge เมื่อระบบเหล่านั้น + สังเคราะห์คำตอบแบบ private หรือ special-use ที่อยู่นอกช่วง benchmark ของ RFC 2544 + ปิดไว้สำหรับการเข้าถึง Telegram ผ่านอินเทอร์เน็ตสาธารณะปกติ - การ override ด้วย environment (ชั่วคราว): @@ -943,25 +980,25 @@ dig +short api.telegram.org AAAA -ความช่วยเหลือเพิ่มเติม: [การแก้ไขปัญหา Channel](/th/channels/troubleshooting) +ความช่วยเหลือเพิ่มเติม: [การแก้ไขปัญหาช่องทาง](/th/channels/troubleshooting). -## อ้างอิงการกำหนดค่า +## ข้อมูลอ้างอิงการกำหนดค่า -อ้างอิงหลัก: [อ้างอิงการกำหนดค่า - Telegram](/th/gateway/config-channels#telegram) +ข้อมูลอ้างอิงหลัก: [ข้อมูลอ้างอิงการกำหนดค่า - Telegram](/th/gateway/config-channels#telegram). - + -- การเริ่มต้น/การยืนยันตัวตน: `enabled`, `botToken`, `tokenFile`, `accounts.*` (`tokenFile` ต้องชี้ไปยังไฟล์ปกติ; symlink จะถูกปฏิเสธ) +- การเริ่มต้น/การยืนยันตัวตน: `enabled`, `botToken`, `tokenFile`, `accounts.*` (`tokenFile` ต้องชี้ไปยังไฟล์ปกติ; symlinks จะถูกปฏิเสธ) - การควบคุมการเข้าถึง: `dmPolicy`, `allowFrom`, `groupPolicy`, `groupAllowFrom`, `groups`, `groups.*.topics.*`, `bindings[]` ระดับบนสุด (`type: "acp"`) - การอนุมัติ exec: `execApprovals`, `accounts.*.execApprovals` - คำสั่ง/เมนู: `commands.native`, `commands.nativeSkills`, `customCommands` -- threading/replies: `replyToMode`, `dm.threadReplies`, `direct.*.threadReplies` -- streaming: `streaming` (preview), `streaming.preview.toolProgress`, `blockStreaming` +- เธรด/การตอบกลับ: `replyToMode`, `dm.threadReplies`, `direct.*.threadReplies` +- การสตรีม: `streaming` (พรีวิว), `streaming.preview.toolProgress`, `blockStreaming` - การจัดรูปแบบ/การส่งมอบ: `textChunkLimit`, `chunkMode`, `linkPreview`, `responsePrefix` - สื่อ/เครือข่าย: `mediaMaxMb`, `mediaGroupFlushMs`, `timeoutSeconds`, `pollingStallThresholdMs`, `retry`, `network.autoSelectFamily`, `network.dangerouslyAllowPrivateNetwork`, `proxy` -- root API แบบกำหนดเอง: `apiRoot` (เฉพาะ root ของ Bot API เท่านั้น; อย่าใส่ `/bot`) +- root API แบบกำหนดเอง: `apiRoot` (root ของ Bot API เท่านั้น; อย่าใส่ `/bot`) - webhook: `webhookUrl`, `webhookSecret`, `webhookPath`, `webhookHost` -- actions/capabilities: `capabilities.inlineButtons`, `actions.sendMessage|editMessage|deleteMessage|reactions|sticker` +- การกระทำ/ความสามารถ: `capabilities.inlineButtons`, `actions.sendMessage|editMessage|deleteMessage|reactions|sticker` - reactions: `reactionNotifications`, `reactionLevel` - ข้อผิดพลาด: `errorPolicy`, `errorCooldownMs` - การเขียน/ประวัติ: `configWrites`, `historyLimit`, `dmHistoryLimit`, `dms.*.historyLimit` @@ -969,28 +1006,28 @@ dig +short api.telegram.org AAAA -ลำดับความสำคัญของหลายบัญชี: เมื่อกำหนดค่า ID บัญชีตั้งแต่สองรายการขึ้นไป ให้ตั้ง `channels.telegram.defaultAccount` (หรือใส่ `channels.telegram.accounts.default`) เพื่อทำให้ routing เริ่มต้นชัดเจน มิฉะนั้น OpenClaw จะ fallback ไปยัง ID บัญชีที่ normalize แล้วรายการแรก และ `openclaw doctor` จะเตือน บัญชีที่มีชื่อจะสืบทอด `channels.telegram.allowFrom` / `groupAllowFrom` แต่ไม่สืบทอดค่า `accounts.default.*` +ลำดับความสำคัญของหลายบัญชี: เมื่อกำหนดค่า ID บัญชีตั้งแต่สองรายการขึ้นไป ให้ตั้ง `channels.telegram.defaultAccount` (หรือใส่ `channels.telegram.accounts.default`) เพื่อทำให้การกำหนดเส้นทางเริ่มต้นชัดเจน มิฉะนั้น OpenClaw จะ fallback ไปยัง ID บัญชีแรกที่ถูกทำให้เป็นรูปแบบปกติ และ `openclaw doctor` จะเตือน บัญชีที่มีชื่อจะสืบทอด `channels.telegram.allowFrom` / `groupAllowFrom` แต่ไม่สืบทอดค่า `accounts.default.*` ## ที่เกี่ยวข้อง - จับคู่ผู้ใช้ Telegram กับ gateway + จับคู่ผู้ใช้ Telegram กับ Gateway พฤติกรรม allowlist ของกลุ่มและหัวข้อ - - Route ข้อความขาเข้าไปยัง agent + + กำหนดเส้นทางข้อความขาเข้าไปยังเอเจนต์ - threat model และการ hardening + แบบจำลองภัยคุกคามและการเสริมความแข็งแกร่ง - - map กลุ่มและหัวข้อไปยัง agent + + จับคู่กลุ่มและหัวข้อกับเอเจนต์ - การวินิจฉัยข้าม channel + การวินิจฉัยข้ามช่องทาง diff --git a/docs/th/ci.md b/docs/th/ci.md index d67339f0d..cda7d2d7b 100644 --- a/docs/th/ci.md +++ b/docs/th/ci.md @@ -1,94 +1,94 @@ --- read_when: - - คุณต้องเข้าใจว่าเหตุใดงาน CI จึงถูกเรียกใช้หรือไม่ถูกเรียกใช้ + - คุณจำเป็นต้องเข้าใจว่าเหตุใดงาน CI จึงทำงานหรือไม่ทำงาน - คุณกำลังดีบักการตรวจสอบ GitHub Actions ที่ล้มเหลว - - คุณกำลังประสานงานการรันหรือการรันซ้ำสำหรับการตรวจสอบความถูกต้องของรีลีส - - คุณกำลังเปลี่ยนการ dispatch ของ ClawSweeper หรือการส่งต่อกิจกรรม GitHub -summary: กราฟงาน CI, เกตตามขอบเขต, ร่มการเผยแพร่, และคำสั่งภายในเครื่องที่เทียบเท่า + - คุณกำลังประสานงานการรันหรือการรันซ้ำการตรวจสอบความถูกต้องของรีลีส + - คุณกำลังเปลี่ยนการส่งงานของ ClawSweeper หรือการส่งต่อกิจกรรมของ GitHub +summary: กราฟงาน CI, เกตตามขอบเขต, ชุดครอบการเผยแพร่ และคำสั่งภายในเครื่องที่เทียบเท่า title: ไปป์ไลน์ CI x-i18n: - generated_at: "2026-05-03T21:27:40Z" + generated_at: "2026-05-04T07:03:26Z" model: gpt-5.5 provider: openai - source_hash: e07fc44aa844cb66ce529c570cbbbbf502a61bcbcbc3d9488557abb459ef7678 + source_hash: 72959d0feaf1339f01c9da263153fd89cc4727da6f928933819931991222714d source_path: ci.md workflow: 16 --- -OpenClaw CI ทำงานในทุก push ไปยัง `main` และทุก pull request งาน `preflight` จะจำแนก diff และปิด lane ที่มีค่าใช้จ่ายสูงเมื่อมีเฉพาะพื้นที่ที่ไม่เกี่ยวข้องเปลี่ยนแปลง การรัน `workflow_dispatch` แบบแมนนวลตั้งใจข้ามการกำหนดขอบเขตอัจฉริยะและกระจายเป็นกราฟเต็มสำหรับ release candidate และการตรวจสอบแบบกว้าง lane ของ Android ยังคงเป็นแบบ opt-in ผ่าน `include_android` ความครอบคลุมของ Plugin สำหรับ release เท่านั้นอยู่ในเวิร์กโฟลว์ [`Plugin Prerelease`](#plugin-prerelease) แยกต่างหาก และจะรันจาก [`Full Release Validation`](#full-release-validation) หรือการ dispatch แบบแมนนวลที่ระบุชัดเจนเท่านั้น +CI ของ OpenClaw ทำงานบนทุกการ push ไปยัง `main` และทุกคำขอดึง งาน `preflight` จัดประเภท diff และปิดเลนที่มีค่าใช้จ่ายสูงเมื่อมีเฉพาะพื้นที่ที่ไม่เกี่ยวข้องเปลี่ยนแปลง การรัน `workflow_dispatch` แบบแมนนวลตั้งใจข้ามการกำหนดขอบเขตแบบอัจฉริยะและกระจายไปยังกราฟเต็มสำหรับตัวเลือกรุ่นเผยแพร่และการตรวจสอบแบบกว้าง เลน Android ยังคงเป็นแบบเลือกเปิดผ่าน `include_android` ความครอบคลุม Plugin เฉพาะรุ่นเผยแพร่อยู่ในเวิร์กโฟลว์ [`Plugin Prerelease`](#plugin-prerelease) แยกต่างหาก และทำงานจาก [`Full Release Validation`](#full-release-validation) หรือการสั่งรันแบบแมนนวลอย่างชัดเจนเท่านั้น ## ภาพรวม Pipeline -| งาน | วัตถุประสงค์ | รันเมื่อ | +| งาน | วัตถุประสงค์ | ทำงานเมื่อ | | -------------------------------- | --------------------------------------------------------------------------------------------------------- | ---------------------------------- | -| `preflight` | ตรวจจับการเปลี่ยนแปลงเฉพาะเอกสาร ขอบเขตที่เปลี่ยนแปลง ส่วนขยายที่เปลี่ยนแปลง และสร้าง manifest ของ CI | เสมอเมื่อเป็น push และ PR ที่ไม่ใช่ draft | -| `security-scm-fast` | ตรวจจับ private key และตรวจสอบเวิร์กโฟลว์ผ่าน `zizmor` | เสมอเมื่อเป็น push และ PR ที่ไม่ใช่ draft | -| `security-dependency-audit` | ตรวจสอบ lockfile ฝั่ง production โดยไม่ติดตั้ง dependency เทียบกับคำแนะนำด้านความปลอดภัยของ npm | เสมอเมื่อเป็น push และ PR ที่ไม่ใช่ draft | -| `security-fast` | aggregate ที่จำเป็นสำหรับงานความปลอดภัยแบบเร็ว | เสมอเมื่อเป็น push และ PR ที่ไม่ใช่ draft | -| `check-dependencies` | รอบตรวจ dependency เฉพาะของ Production Knip พร้อมตัวป้องกัน allowlist ของไฟล์ที่ไม่ได้ใช้ | การเปลี่ยนแปลงที่เกี่ยวข้องกับ Node | -| `build-artifacts` | สร้าง `dist/`, Control UI, การตรวจ artifact ที่ build แล้ว และ artifact ปลายน้ำที่ใช้ซ้ำได้ | การเปลี่ยนแปลงที่เกี่ยวข้องกับ Node | -| `checks-fast-core` | lane ตรวจความถูกต้องบน Linux แบบเร็ว เช่น การตรวจ bundled/plugin-contract/protocol | การเปลี่ยนแปลงที่เกี่ยวข้องกับ Node | -| `checks-fast-contracts-channels` | การตรวจ contract ของ channel แบบแบ่ง shard พร้อมผลตรวจ aggregate ที่เสถียร | การเปลี่ยนแปลงที่เกี่ยวข้องกับ Node | -| `checks-node-core-test` | shard ทดสอบ Core Node โดยไม่รวม lane ของ channel, bundled, contract และ extension | การเปลี่ยนแปลงที่เกี่ยวข้องกับ Node | -| `check` | เทียบเท่า gate หลักภายในแบบแบ่ง shard: type ของ prod, lint, guard, type ของ test และ strict smoke | การเปลี่ยนแปลงที่เกี่ยวข้องกับ Node | -| `check-additional` | architecture, drift ของ boundary/prompt แบบแบ่ง shard, guard ของ extension, package boundary และ gateway watch | การเปลี่ยนแปลงที่เกี่ยวข้องกับ Node | -| `build-smoke` | การทดสอบ smoke ของ CLI ที่ build แล้ว และ smoke ของหน่วยความจำตอนเริ่มต้น | การเปลี่ยนแปลงที่เกี่ยวข้องกับ Node | -| `checks` | ตัวตรวจสอบสำหรับการทดสอบ channel ของ artifact ที่ build แล้ว | การเปลี่ยนแปลงที่เกี่ยวข้องกับ Node | -| `checks-node-compat-node22` | lane build และ smoke สำหรับความเข้ากันได้กับ Node 22 | การ dispatch CI แบบแมนนวลสำหรับ release | -| `check-docs` | การตรวจ format, lint และลิงก์เสียของเอกสาร | เอกสารเปลี่ยนแปลง | +| `preflight` | ตรวจจับการเปลี่ยนแปลงเฉพาะเอกสาร ขอบเขตที่เปลี่ยนแปลง ส่วนขยายที่เปลี่ยนแปลง และสร้างแมนิเฟสต์ CI | เสมอบน push และ PR ที่ไม่ใช่ฉบับร่าง | +| `security-scm-fast` | การตรวจจับคีย์ส่วนตัวและการตรวจสอบเวิร์กโฟลว์ผ่าน `zizmor` | เสมอบน push และ PR ที่ไม่ใช่ฉบับร่าง | +| `security-dependency-audit` | การตรวจสอบ lockfile สำหรับโปรดักชันแบบไม่มี dependency เทียบกับคำแนะนำด้านความปลอดภัยของ npm | เสมอบน push และ PR ที่ไม่ใช่ฉบับร่าง | +| `security-fast` | ผลรวมที่บังคับใช้สำหรับงานความปลอดภัยแบบเร็ว | เสมอบน push และ PR ที่ไม่ใช่ฉบับร่าง | +| `check-dependencies` | การผ่านเฉพาะ dependency ของ Knip สำหรับโปรดักชัน พร้อมตัวป้องกัน allowlist ของไฟล์ที่ไม่ได้ใช้ | การเปลี่ยนแปลงที่เกี่ยวข้องกับ Node | +| `build-artifacts` | สร้าง `dist/`, Control UI, การตรวจสอบอาร์ติแฟกต์ที่ build แล้ว และอาร์ติแฟกต์ปลายทางที่ใช้ซ้ำได้ | การเปลี่ยนแปลงที่เกี่ยวข้องกับ Node | +| `checks-fast-core` | เลนความถูกต้องของ Linux แบบเร็ว เช่น การตรวจสอบ bundled/plugin-contract/protocol | การเปลี่ยนแปลงที่เกี่ยวข้องกับ Node | +| `checks-fast-contracts-channels` | การตรวจสอบสัญญา channel แบบแบ่งชาร์ด พร้อมผลตรวจสอบรวมที่เสถียร | การเปลี่ยนแปลงที่เกี่ยวข้องกับ Node | +| `checks-node-core-test` | ชาร์ดทดสอบ Node ส่วน core ยกเว้นเลน channel, bundled, contract และ extension | การเปลี่ยนแปลงที่เกี่ยวข้องกับ Node | +| `check` | เทียบเท่า gate หลักในเครื่องแบบแบ่งชาร์ด: ประเภทโปรดักชัน, lint, guards, ประเภทการทดสอบ และ smoke แบบเข้มงวด | การเปลี่ยนแปลงที่เกี่ยวข้องกับ Node | +| `check-additional` | สถาปัตยกรรม, boundary/prompt drift แบบแบ่งชาร์ด, guard ของ extension, boundary ของ package และ gateway watch | การเปลี่ยนแปลงที่เกี่ยวข้องกับ Node | +| `build-smoke` | การทดสอบ smoke ของ CLI ที่ build แล้ว และ smoke หน่วยความจำตอนเริ่มทำงาน | การเปลี่ยนแปลงที่เกี่ยวข้องกับ Node | +| `checks` | ตัวตรวจยืนยันสำหรับการทดสอบ channel ของอาร์ติแฟกต์ที่ build แล้ว | การเปลี่ยนแปลงที่เกี่ยวข้องกับ Node | +| `checks-node-compat-node22` | เลน build และ smoke สำหรับความเข้ากันได้กับ Node 22 | การสั่งรัน CI แบบแมนนวลสำหรับรุ่นเผยแพร่ | +| `check-docs` | การจัดรูปแบบเอกสาร, lint และการตรวจสอบลิงก์เสีย | เอกสารเปลี่ยนแปลง | | `skills-python` | Ruff + pytest สำหรับ Skills ที่มี Python รองรับ | การเปลี่ยนแปลงที่เกี่ยวข้องกับ Python-skill | -| `checks-windows` | การทดสอบ process/path เฉพาะ Windows พร้อม regression ของ runtime import specifier ที่ใช้ร่วมกัน | การเปลี่ยนแปลงที่เกี่ยวข้องกับ Windows | -| `macos-node` | lane ทดสอบ TypeScript บน macOS โดยใช้ artifact ที่ build แล้วร่วมกัน | การเปลี่ยนแปลงที่เกี่ยวข้องกับ macOS | -| `macos-swift` | Swift lint, build และ test สำหรับแอป macOS | การเปลี่ยนแปลงที่เกี่ยวข้องกับ macOS | -| `android` | unit test ของ Android สำหรับทั้งสอง flavor พร้อมการ build debug APK หนึ่งรายการ | การเปลี่ยนแปลงที่เกี่ยวข้องกับ Android | -| `test-performance-agent` | การปรับปรุงการทดสอบช้าของ Codex รายวันหลังจากกิจกรรมที่เชื่อถือได้ | CI หลักสำเร็จหรือ dispatch แบบแมนนวล | -| `openclaw-performance` | รายงานประสิทธิภาพ runtime ของ Kova แบบรายวัน/ตามคำขอ พร้อม lane mock-provider, deep-profile และ GPT 5.4 live | ตามกำหนดเวลาและ dispatch แบบแมนนวล | +| `checks-windows` | การทดสอบ process/path เฉพาะ Windows พร้อม regression ของตัวระบุ import รันไทม์ร่วม | การเปลี่ยนแปลงที่เกี่ยวข้องกับ Windows | +| `macos-node` | เลนทดสอบ TypeScript บน macOS โดยใช้อาร์ติแฟกต์ที่ build แล้วร่วมกัน | การเปลี่ยนแปลงที่เกี่ยวข้องกับ macOS | +| `macos-swift` | Swift lint, build และทดสอบสำหรับแอป macOS | การเปลี่ยนแปลงที่เกี่ยวข้องกับ macOS | +| `android` | การทดสอบหน่วย Android สำหรับทั้งสอง flavor พร้อมการ build debug APK หนึ่งรายการ | การเปลี่ยนแปลงที่เกี่ยวข้องกับ Android | +| `test-performance-agent` | การเพิ่มประสิทธิภาพการทดสอบช้ารายวันของ Codex หลังจากกิจกรรมที่เชื่อถือได้ | CI หลักสำเร็จหรือสั่งรันแบบแมนนวล | +| `openclaw-performance` | รายงานประสิทธิภาพรันไทม์ Kova รายวัน/ตามต้องการ พร้อมเลน mock-provider, deep-profile และ GPT 5.4 แบบ live | ตามกำหนดเวลาและสั่งรันแบบแมนนวล | ## ลำดับ Fail-fast -1. `preflight` ตัดสินใจว่า lane ใดมีอยู่ตั้งแต่ต้น ตรรกะ `docs-scope` และ `changed-scope` เป็นขั้นตอนภายในงานนี้ ไม่ใช่งานแยกต่างหาก -2. `security-scm-fast`, `security-dependency-audit`, `security-fast`, `check`, `check-additional`, `check-docs` และ `skills-python` ล้มเหลวอย่างรวดเร็วโดยไม่ต้องรอ artifact และงาน matrix ของแพลตฟอร์มที่หนักกว่า -3. `build-artifacts` ทำงานทับซ้อนกับ lane Linux แบบเร็ว เพื่อให้ผู้ใช้ปลายน้ำเริ่มได้ทันทีที่ build ร่วมพร้อม -4. lane แพลตฟอร์มและ runtime ที่หนักกว่าจะกระจายงานหลังจากนั้น: `checks-fast-core`, `checks-fast-contracts-channels`, `checks-node-core-test`, `checks`, `checks-windows`, `macos-node`, `macos-swift` และ `android` +1. `preflight` ตัดสินใจว่าเลนใดมีอยู่ตั้งแต่แรก ตรรกะ `docs-scope` และ `changed-scope` เป็นขั้นตอนภายในงานนี้ ไม่ใช่งานแยกต่างหาก +2. `security-scm-fast`, `security-dependency-audit`, `security-fast`, `check`, `check-additional`, `check-docs` และ `skills-python` ล้มเหลวได้อย่างรวดเร็วโดยไม่ต้องรอ matrix ของอาร์ติแฟกต์และแพลตฟอร์มที่หนักกว่า +3. `build-artifacts` ทำงานทับซ้อนกับเลน Linux แบบเร็ว เพื่อให้ผู้ใช้ปลายทางเริ่มได้ทันทีที่ build ร่วมพร้อมใช้งาน +4. เลนแพลตฟอร์มและรันไทม์ที่หนักกว่าจะกระจายออกหลังจากนั้น: `checks-fast-core`, `checks-fast-contracts-channels`, `checks-node-core-test`, `checks`, `checks-windows`, `macos-node`, `macos-swift` และ `android` -GitHub อาจทำเครื่องหมายงานที่ถูกแทนที่เป็น `cancelled` เมื่อมี push ใหม่กว่าลงบน PR เดียวกันหรือ ref `main` เดียวกัน ให้ถือว่านั่นเป็น noise ของ CI เว้นแต่การรันล่าสุดสำหรับ ref เดียวกันจะล้มเหลวด้วย การตรวจ aggregate shard ใช้ `!cancelled() && always()` เพื่อให้ยังรายงาน shard failure ปกติ แต่ไม่เข้าคิวหลังจากเวิร์กโฟลว์ทั้งหมดถูกแทนที่ไปแล้ว concurrency key ของ CI อัตโนมัติมีการ version (`CI-v7-*`) เพื่อให้ zombie ฝั่ง GitHub ในกลุ่มคิวเก่าไม่สามารถบล็อกการรัน main ใหม่ได้ไม่มีกำหนด การรันชุดเต็มแบบแมนนวลใช้ `CI-manual-v1-*` และไม่ยกเลิกการรันที่กำลังดำเนินอยู่ +GitHub อาจทำเครื่องหมายงานที่ถูกแทนที่เป็น `cancelled` เมื่อมี push ใหม่กว่าเข้ามาบน PR เดียวกันหรือ ref `main` เดียวกัน ให้ถือว่าสิ่งนั้นเป็นสัญญาณรบกวนของ CI เว้นแต่ว่าการรันล่าสุดสำหรับ ref เดียวกันก็ล้มเหลวด้วย การตรวจสอบชาร์ดแบบรวมใช้ `!cancelled() && always()` เพื่อให้ยังรายงานความล้มเหลวปกติของชาร์ด แต่ไม่เข้าคิวหลังจากทั้งเวิร์กโฟลว์ถูกแทนที่แล้ว คีย์ concurrency อัตโนมัติของ CI มีเวอร์ชัน (`CI-v7-*`) เพื่อไม่ให้ซอมบี้ฝั่ง GitHub ในกลุ่มคิวเก่าบล็อกการรัน main ที่ใหม่กว่าอย่างไม่มีกำหนด การรันชุดเต็มแบบแมนนวลใช้ `CI-manual-v1-*` และไม่ยกเลิกการรันที่กำลังดำเนินอยู่ ## ขอบเขตและการกำหนดเส้นทาง -ตรรกะขอบเขตอยู่ใน `scripts/ci-changed-scope.mjs` และครอบคลุมด้วย unit test ใน `src/scripts/ci-changed-scope.test.ts` การ dispatch แบบแมนนวลจะข้ามการตรวจจับ changed-scope และทำให้ manifest ของ preflight ทำงานเหมือนทุกพื้นที่ที่มีขอบเขตเปลี่ยนแปลง +ตรรกะขอบเขตอยู่ใน `scripts/ci-changed-scope.mjs` และครอบคลุมด้วยการทดสอบหน่วยใน `src/scripts/ci-changed-scope.test.ts` การสั่งรันแบบแมนนวลข้ามการตรวจจับ changed-scope และทำให้แมนิเฟสต์ preflight ทำตัวเหมือนทุกพื้นที่ที่มีขอบเขตเปลี่ยนแปลง -- **การแก้ไขเวิร์กโฟลว์ CI** ตรวจสอบกราฟ Node CI พร้อม workflow linting แต่ไม่ได้บังคับ build native ของ Windows, Android หรือ macOS ด้วยตัวเอง lane แพลตฟอร์มเหล่านั้นยังคงจำกัดขอบเขตตามการเปลี่ยนแปลงซอร์สของแพลตฟอร์ม -- **การแก้ไขเฉพาะ routing ของ CI, การแก้ไข fixture ของ core-test ราคาถูกที่เลือกไว้ และการแก้ไข helper/test-routing ของ plugin contract แบบแคบ** ใช้เส้นทาง manifest แบบเร็วเฉพาะ Node: `preflight`, security และงาน `checks-fast-core` เพียงงานเดียว เส้นทางนั้นข้าม build artifact, ความเข้ากันได้กับ Node 22, channel contract, shard core เต็ม, shard bundled-plugin และ matrix guard เพิ่มเติม เมื่อการเปลี่ยนแปลงจำกัดอยู่ที่พื้นผิว routing หรือ helper ที่งานเร็วทดสอบโดยตรง -- **การตรวจ Windows Node** จำกัดขอบเขตอยู่ที่ wrapper ของ process/path เฉพาะ Windows, helper ของ npm/pnpm/UI runner, config ของ package manager และพื้นผิวเวิร์กโฟลว์ CI ที่เรียกใช้ lane นั้น การเปลี่ยนแปลง source, plugin, install-smoke และเฉพาะ test ที่ไม่เกี่ยวข้องยังคงอยู่บน lane Linux Node +- **การแก้ไขเวิร์กโฟลว์ CI** ตรวจสอบกราฟ CI ของ Node พร้อม workflow linting แต่ไม่บังคับ build แบบ native ของ Windows, Android หรือ macOS ด้วยตัวเอง เลนแพลตฟอร์มเหล่านั้นยังคงถูกกำหนดขอบเขตตามการเปลี่ยนแปลงซอร์สของแพลตฟอร์ม +- **การแก้ไขเฉพาะการกำหนดเส้นทาง CI, การแก้ไข fixture ของ core-test ราคาถูกบางส่วน และการแก้ไข helper/test-routing ของ plugin contract แบบแคบ** ใช้เส้นทางแมนิเฟสต์ Node-only แบบเร็ว: `preflight`, security และงาน `checks-fast-core` เดี่ยว เส้นทางนั้นข้ามอาร์ติแฟกต์ build, ความเข้ากันได้กับ Node 22, channel contracts, ชาร์ด core เต็ม, ชาร์ด bundled-plugin และ matrix guard เพิ่มเติม เมื่อการเปลี่ยนแปลงจำกัดอยู่ที่พื้นผิว routing หรือ helper ที่งานเร็วทดสอบโดยตรง +- **การตรวจสอบ Node บน Windows** ถูกกำหนดขอบเขตไว้ที่ wrapper ของ process/path เฉพาะ Windows, helper ของ npm/pnpm/UI runner, การกำหนดค่า package manager และพื้นผิวเวิร์กโฟลว์ CI ที่เรียกใช้เลนนั้น การเปลี่ยนแปลงซอร์ส, plugin, install-smoke และเฉพาะการทดสอบที่ไม่เกี่ยวข้องจะยังอยู่บนเลน Linux Node -กลุ่มทดสอบ Node ที่ช้าที่สุดถูกแยกหรือถ่วงน้ำหนักให้สมดุลเพื่อให้งานแต่ละงานยังเล็กโดยไม่จอง runner เกินจำเป็น: channel contract รันเป็น shard ถ่วงน้ำหนักสามชุด, lane core unit fast/support รันแยกกัน, infra runtime core ถูกแยกระหว่าง shard state และ process/config, auto-reply รันเป็น worker ที่สมดุล (โดยแยก subtree ของ reply เป็น shard agent-runner, dispatch และ commands/state-routing) และ config ของ agentic gateway/server ถูกแยกข้าม lane chat/auth/model/http-plugin/runtime/startup แทนที่จะรอ artifact ที่ build แล้ว การทดสอบ browser, QA, media และ Plugin อื่นๆ แบบกว้างใช้ config Vitest เฉพาะของตัวเองแทน plugin catch-all ร่วม Shard แบบ include-pattern บันทึกรายการเวลาโดยใช้ชื่อ shard ของ CI ดังนั้น `.artifacts/vitest-shard-timings.json` จึงแยกทั้ง config ออกจาก shard ที่ถูกกรองได้ `check-additional` เก็บงาน compile/canary ของ package-boundary ไว้ด้วยกัน และแยก architecture ของ runtime topology ออกจากความครอบคลุมของ gateway watch รายการ boundary guard ถูก stripe ข้าม matrix shard สี่ชุด โดยแต่ละชุดรัน guard อิสระที่เลือกไว้พร้อมกันและพิมพ์เวลาต่อการตรวจ รวมถึง `pnpm prompt:snapshots:check` เพื่อให้ prompt drift ของ happy path runtime Codex ถูกผูกกับ PR ที่ทำให้เกิดขึ้น Gateway watch, การทดสอบ channel และ shard core support-boundary รันพร้อมกันภายใน `build-artifacts` หลังจาก `dist/` และ `dist-runtime/` ถูก build แล้ว +ครอบครัวการทดสอบ Node ที่ช้าที่สุดถูกแบ่งหรือถ่วงสมดุลเพื่อให้งานแต่ละงานยังเล็กโดยไม่จอง runner มากเกินไป: channel contracts รันเป็นชาร์ดถ่วงน้ำหนักสามชาร์ด, เลน core unit fast/support รันแยกกัน, โครงสร้างพื้นฐานรันไทม์ core ถูกแบ่งระหว่างชาร์ด state และ process/config, auto-reply รันเป็น worker ที่สมดุล (โดย subtree ของ reply แบ่งเป็นชาร์ด agent-runner, dispatch และ commands/state-routing) และการกำหนดค่า gateway/server แบบ agentic ถูกแบ่งข้ามเลน chat/auth/model/http-plugin/runtime/startup แทนการรออาร์ติแฟกต์ที่ build แล้ว การทดสอบ browser, QA, media และ plugin เบ็ดเตล็ดแบบกว้างใช้การกำหนดค่า Vitest เฉพาะของตนแทน catch-all plugin ร่วม ชาร์ด include-pattern บันทึกรายการเวลาโดยใช้ชื่อชาร์ด CI เพื่อให้ `.artifacts/vitest-shard-timings.json` แยก config ทั้งชุดออกจากชาร์ดที่ถูกกรองได้ `check-additional` เก็บงาน compile/canary ของ package-boundary ไว้ด้วยกัน และแยกสถาปัตยกรรม runtime topology ออกจากความครอบคลุมของ gateway watch รายการ boundary guard ถูกกระจายเป็นแถบข้าม matrix สี่ชาร์ด โดยแต่ละชาร์ดรัน guard อิสระที่เลือกไว้พร้อมกัน และพิมพ์เวลาต่อการตรวจสอบ รวมถึง `pnpm prompt:snapshots:check` เพื่อให้ prompt drift ของ happy-path ในรันไทม์ Codex ถูกตรึงไว้กับ PR ที่ก่อให้เกิดมัน Gateway watch, การทดสอบ channel และชาร์ด core support-boundary รันพร้อมกันภายใน `build-artifacts` หลังจาก `dist/` และ `dist-runtime/` ถูก build แล้ว -Android CI รันทั้ง `testPlayDebugUnitTest` และ `testThirdPartyDebugUnitTest` จากนั้น build Play debug APK flavor ของ third-party ไม่มี source set หรือ manifest แยกต่างหาก lane unit-test ของมันยังคง compile flavor ด้วย flag BuildConfig ของ SMS/call-log ขณะหลีกเลี่ยงงาน packaging debug APK ซ้ำในทุก push ที่เกี่ยวข้องกับ Android +CI ของ Android รันทั้ง `testPlayDebugUnitTest` และ `testThirdPartyDebugUnitTest` แล้วจึง build Play debug APK flavor ของบุคคลที่สามไม่มี source set หรือ manifest แยกต่างหาก เลน unit-test ของมันยังคง compile flavor พร้อมแฟล็ก SMS/call-log ของ BuildConfig ขณะหลีกเลี่ยงงาน packaging debug APK ซ้ำในทุก push ที่เกี่ยวข้องกับ Android -Shard `check-dependencies` รัน `pnpm deadcode:dependencies` (รอบตรวจ dependency เฉพาะ production ของ Knip ที่ pin กับ Knip เวอร์ชันล่าสุด โดยปิดอายุ release ขั้นต่ำของ pnpm สำหรับการติดตั้ง `dlx`) และ `pnpm deadcode:unused-files` ซึ่งเทียบผลค้นหาไฟล์ production ที่ไม่ได้ใช้ของ Knip กับ `scripts/deadcode-unused-files.allowlist.mjs` guard ของไฟล์ที่ไม่ได้ใช้จะล้มเหลวเมื่อ PR เพิ่มไฟล์ที่ไม่ได้ใช้และยังไม่ได้ review ใหม่ หรือปล่อยรายการ allowlist ที่ stale ไว้ พร้อมยังรักษาพื้นผิว dynamic plugin, generated, build, live-test และ package bridge ที่ตั้งใจไว้ซึ่ง Knip ไม่สามารถ resolve แบบ static ได้ +ชาร์ด `check-dependencies` รัน `pnpm deadcode:dependencies` (การผ่านเฉพาะ dependency ของ Knip สำหรับโปรดักชันที่ตรึงกับเวอร์ชัน Knip ล่าสุด โดยปิดใช้อายุรุ่นเผยแพร่ขั้นต่ำของ pnpm สำหรับการติดตั้ง `dlx`) และ `pnpm deadcode:unused-files` ซึ่งเปรียบเทียบการพบไฟล์ที่ไม่ได้ใช้ของ Knip ในโปรดักชันกับ `scripts/deadcode-unused-files.allowlist.mjs` ตัวป้องกันไฟล์ที่ไม่ได้ใช้จะล้มเหลวเมื่อ PR เพิ่มไฟล์ที่ไม่ได้ใช้ซึ่งยังไม่ผ่านการตรวจสอบใหม่ หรือทิ้งรายการ allowlist ที่ล้าสมัยไว้ ขณะยังคงรักษาพื้นผิว dynamic plugin, generated, build, live-test และ package bridge ที่ตั้งใจไว้ซึ่ง Knip ไม่สามารถ resolve แบบ static ได้ ## การส่งต่อกิจกรรม ClawSweeper -`.github/workflows/clawsweeper-dispatch.yml` คือสะพานฝั่งปลายทางจากกิจกรรม repository ของ OpenClaw ไปยัง ClawSweeper มันไม่ checkout หรือ execute โค้ด pull request ที่ไม่น่าเชื่อถือ เวิร์กโฟลว์สร้าง GitHub App token จาก `CLAWSWEEPER_APP_PRIVATE_KEY` จากนั้น dispatch payload `repository_dispatch` ขนาดกะทัดรัดไปยัง `openclaw/clawsweeper` +`.github/workflows/clawsweeper-dispatch.yml` เป็น bridge ฝั่งเป้าหมายจากกิจกรรม repository ของ OpenClaw ไปยัง ClawSweeper มันไม่ checkout หรือดำเนินการโค้ดคำขอดึงที่ไม่น่าเชื่อถือ เวิร์กโฟลว์สร้าง token ของ GitHub App จาก `CLAWSWEEPER_APP_PRIVATE_KEY` แล้ว dispatch payload `repository_dispatch` แบบกะทัดรัดไปยัง `openclaw/clawsweeper` -เวิร์กโฟลว์มีสี่ lane: +เวิร์กโฟลว์มีสี่เลน: -- `clawsweeper_item` สำหรับคำขอ review issue และ pull request แบบเจาะจง; -- `clawsweeper_comment` สำหรับคำสั่ง ClawSweeper ที่ชัดเจนใน comment ของ issue; -- `clawsweeper_commit_review` สำหรับคำขอ review ระดับ commit บน push ไปยัง `main`; -- `github_activity` สำหรับกิจกรรม GitHub ทั่วไปที่ agent ของ ClawSweeper อาจตรวจดู +- `clawsweeper_item` สำหรับคำขอตรวจ review issue และ pull request แบบเจาะจง +- `clawsweeper_comment` สำหรับคำสั่ง ClawSweeper อย่างชัดเจนในคอมเมนต์ issue +- `clawsweeper_commit_review` สำหรับคำขอตรวจ review ระดับ commit บน push ไปยัง `main` +- `github_activity` สำหรับกิจกรรม GitHub ทั่วไปที่ agent ClawSweeper อาจตรวจสอบ -lane `github_activity` ส่งต่อเฉพาะ metadata ที่ normalize แล้ว: ประเภท event, action, actor, repository, หมายเลข item, URL, title, state และ excerpt สั้นๆ สำหรับ comment หรือ review เมื่อมี มันตั้งใจหลีกเลี่ยงการส่งต่อ body ของ webhook ทั้งหมด เวิร์กโฟลว์ฝั่งรับใน `openclaw/clawsweeper` คือ `.github/workflows/github-activity.yml` ซึ่งโพสต์ event ที่ normalize แล้วไปยังฮุก OpenClaw Gateway สำหรับ agent ของ ClawSweeper +เลน `github_activity` ส่งต่อเฉพาะ metadata ที่ normalize แล้ว: ประเภท event, action, actor, repository, หมายเลข item, URL, title, state และ excerpt สั้นสำหรับคอมเมนต์หรือ review เมื่อมีอยู่ มันตั้งใจหลีกเลี่ยงการส่งต่อ webhook body ทั้งหมด เวิร์กโฟลว์ที่รับใน `openclaw/clawsweeper` คือ `.github/workflows/github-activity.yml` ซึ่งโพสต์ event ที่ normalize แล้วไปยัง hook ของ OpenClaw Gateway สำหรับ agent ClawSweeper -กิจกรรมทั่วไปคือการสังเกต ไม่ใช่การส่งมอบโดยค่าเริ่มต้น agent ของ ClawSweeper ได้รับเป้าหมาย Discord ใน prompt และควรโพสต์ไปยัง `#clawsweeper` เฉพาะเมื่อ event นั้นน่าประหลาดใจ ดำเนินการได้ มีความเสี่ยง หรือมีประโยชน์ต่อการปฏิบัติการ การเปิด แก้ไข ความเคลื่อนไหวจาก bot, noise จาก webhook ซ้ำ และ traffic review ปกติควรได้ผลลัพธ์เป็น `NO_REPLY` +กิจกรรมทั่วไปคือการสังเกต ไม่ใช่การส่งมอบโดยค่าเริ่มต้น agent ClawSweeper ได้รับเป้าหมาย Discord ใน prompt และควรโพสต์ไปยัง `#clawsweeper` เฉพาะเมื่อ event นั้นน่าประหลาดใจ ดำเนินการได้ มีความเสี่ยง หรือมีประโยชน์ต่อการดำเนินงาน การเปิด การแก้ไข ความเปลี่ยนแปลงจาก bot สัญญาณรบกวน webhook ซ้ำ และทราฟฟิก review ปกติควรให้ผลเป็น `NO_REPLY` -ถือว่า title, comment, body, ข้อความ review, ชื่อ branch และ commit message ของ GitHub เป็นข้อมูลที่ไม่น่าเชื่อถือตลอดเส้นทางนี้ สิ่งเหล่านี้เป็น input สำหรับการสรุปและ triage ไม่ใช่คำสั่งสำหรับเวิร์กโฟลว์หรือ runtime ของ agent +ให้ถือว่า title, คอมเมนต์, body, ข้อความ review, ชื่อ branch และข้อความ commit ของ GitHub เป็นข้อมูลที่ไม่น่าเชื่อถือตลอดเส้นทางนี้ สิ่งเหล่านี้เป็นอินพุตสำหรับการสรุปและ triage ไม่ใช่คำสั่งสำหรับเวิร์กโฟลว์หรือรันไทม์ agent -## การ dispatch แบบแมนนวล +## การสั่งรันแบบแมนนวล -การ dispatch CI แบบแมนนวลจะรันกราฟงานเดียวกับ CI ปกติ แต่บังคับเปิดทุก lane ที่มีขอบเขตแบบ non-Android: Linux Node shards, bundled-plugin shards, channel contracts, ความเข้ากันได้กับ Node 22, `check`, `check-additional`, build smoke, การตรวจสอบเอกสาร, Python skills, Windows, macOS และ Control UI i18n การ dispatch CI แบบแมนนวลแยกเดี่ยวจะรันเฉพาะ Android ด้วย `include_android=true`; umbrella ของการเผยแพร่เต็มรูปแบบจะเปิดใช้ Android โดยส่ง `include_android=true` การตรวจสอบแบบสแตติกก่อนเผยแพร่ของ Plugin, shard `agentic-plugins` ที่ใช้เฉพาะการเผยแพร่, การ sweep แบทช์ส่วนขยายเต็มรูปแบบ และ lane Docker ก่อนเผยแพร่ของ Plugin จะถูกยกเว้นจาก CI ชุดทดสอบ Docker ก่อนเผยแพร่จะรันเฉพาะเมื่อ `Full Release Validation` dispatch workflow `Plugin Prerelease` แยกต่างหากพร้อมเปิดใช้ gate การตรวจสอบความถูกต้องของการเผยแพร่ +การสั่งเรียกใช้ CI ด้วยตนเองจะรันกราฟงานเดียวกับ CI ปกติ แต่บังคับเปิดทุกเลนที่มีขอบเขตไม่ใช่ Android: ชาร์ด Node บน Linux, ชาร์ด Plugin ที่รวมมาในชุด, สัญญาช่องทาง, ความเข้ากันได้กับ Node 22, `check`, `check-additional`, การตรวจสอบ smoke ของบิลด์, การตรวจสอบเอกสาร, Skills ของ Python, Windows, macOS, และ i18n ของ Control UI การสั่งเรียกใช้ CI ด้วยตนเองแบบแยกเดี่ยวจะรันเฉพาะ Android ด้วย `include_android=true`; เวิร์กโฟลว์ครอบคลุมรีลีสแบบเต็มเปิดใช้ Android โดยส่ง `include_android=true` การตรวจสอบแบบ static ก่อนรีลีสของ Plugin, ชาร์ด `agentic-plugins` ที่ใช้เฉพาะรีลีส, การกวาดแบบชุดของส่วนขยายทั้งหมด, และเลน Docker ก่อนรีลีสของ Plugin จะถูกแยกออกจาก CI ชุด Docker ก่อนรีลีสจะรันเฉพาะเมื่อ `Full Release Validation` สั่งเรียกใช้เวิร์กโฟลว์ `Plugin Prerelease` ที่แยกต่างหากพร้อมเปิดใช้เกตการตรวจสอบรีลีส -การรันแบบแมนนวลใช้กลุ่ม concurrency ที่ไม่ซ้ำกัน เพื่อไม่ให้ชุดเต็มของ release candidate ถูกยกเลิกโดยการรัน push หรือ PR อื่นบน ref เดียวกัน อินพุต `target_ref` ที่เป็นทางเลือกช่วยให้ caller ที่เชื่อถือได้รันกราฟนั้นกับ branch, tag หรือ SHA ของ commit แบบเต็ม โดยใช้ไฟล์ workflow จาก dispatch ref ที่เลือก +การรันด้วยตนเองใช้กลุ่มการทำงานพร้อมกันที่ไม่ซ้ำกัน เพื่อไม่ให้ชุดเต็มสำหรับ release candidate ถูกยกเลิกโดยการรัน push หรือ PR อื่นบนตัวอ้างอิงเดียวกัน อินพุต `target_ref` ที่เป็นตัวเลือกเสริมช่วยให้ผู้เรียกใช้ที่เชื่อถือได้รันกราฟนั้นกับสาขา แท็ก หรือ SHA ของคอมมิตแบบเต็ม โดยใช้ไฟล์เวิร์กโฟลว์จากตัวอ้างอิงที่เลือกสำหรับการสั่งเรียกใช้ ```bash gh workflow run ci.yml --ref release/YYYY.M.D @@ -98,17 +98,17 @@ gh workflow run full-release-validation.yml --ref main -f ref= ## รันเนอร์ -| รันเนอร์ | งาน | +| รันเนอร์ | งาน | | -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `ubuntu-24.04` | `preflight`, งานความปลอดภัยแบบเร็วและ aggregate (`security-scm-fast`, `security-dependency-audit`, `security-fast`), การตรวจสอบโปรโตคอล/สัญญา/bundled แบบเร็ว, การตรวจสอบ channel contract แบบ sharded, shard ของ `check` ยกเว้น lint, shard และ aggregate ของ `check-additional`, ตัวตรวจสอบ aggregate ของการทดสอบ Node, การตรวจสอบเอกสาร, Python skills, workflow-sanity, labeler, auto-response; preflight ของ install-smoke ยังใช้ Ubuntu ที่โฮสต์โดย GitHub เพื่อให้เมทริกซ์ Blacksmith เข้าคิวได้เร็วขึ้น | -| `blacksmith-4vcpu-ubuntu-2404` | `CodeQL Critical Quality`, shard ส่วนขยายที่น้ำหนักต่ำกว่า, `checks-fast-core`, `checks-node-compat-node22`, `check-prod-types` และ `check-test-types` | -| `blacksmith-8vcpu-ubuntu-2404` | `build-artifacts`, build-smoke, shard การทดสอบ Linux Node, shard การทดสอบ Plugin ที่ bundled, `android` | -| `blacksmith-16vcpu-ubuntu-2404` | `check-lint` (ไวต่อ CPU มากพอที่ 8 vCPU มีต้นทุนมากกว่าที่ประหยัดได้); build Docker ของ install-smoke (เวลาเข้าคิว 32-vCPU มีต้นทุนมากกว่าที่ประหยัดได้) | +| `ubuntu-24.04` | `preflight`, งานความปลอดภัยแบบเร็วและงานรวมผล (`security-scm-fast`, `security-dependency-audit`, `security-fast`), การตรวจสอบโปรโตคอล/สัญญา/แบบรวมชุดแบบเร็ว, การตรวจสอบสัญญาช่องทางแบบแยกชาร์ด, ชาร์ด `check` ยกเว้น lint, ชาร์ดและงานรวมผล `check-additional`, ตัวตรวจสอบงานรวมผลของการทดสอบ Node, การตรวจสอบเอกสาร, Skills ของ Python, workflow-sanity, labeler, auto-response; preflight ของ install-smoke ยังใช้ Ubuntu ที่ GitHub โฮสต์เพื่อให้เมทริกซ์ Blacksmith เข้าคิวได้เร็วขึ้น | +| `blacksmith-4vcpu-ubuntu-2404` | `CodeQL Critical Quality`, ชาร์ดส่วนขยายที่น้ำหนักเบากว่า, `checks-fast-core`, `checks-node-compat-node22`, `check-prod-types`, และ `check-test-types` | +| `blacksmith-8vcpu-ubuntu-2404` | `build-artifacts`, build-smoke, ชาร์ดทดสอบ Node บน Linux, ชาร์ดทดสอบ Plugin ที่รวมมาในชุด, `android` | +| `blacksmith-16vcpu-ubuntu-2404` | `check-lint` (ไวต่อ CPU มากพอที่ 8 vCPU มีต้นทุนมากกว่าที่ประหยัดได้); บิลด์ Docker ของ install-smoke (เวลาคิว 32-vCPU มีต้นทุนมากกว่าที่ประหยัดได้) | | `blacksmith-16vcpu-windows-2025` | `checks-windows` | -| `blacksmith-6vcpu-macos-latest` | `macos-node` บน `openclaw/openclaw`; fork จะ fallback ไปที่ `macos-latest` | -| `blacksmith-12vcpu-macos-latest` | `macos-swift` บน `openclaw/openclaw`; fork จะ fallback ไปที่ `macos-latest` | +| `blacksmith-6vcpu-macos-latest` | `macos-node` บน `openclaw/openclaw`; คลังที่แยกสำเนาจะย้อนกลับไปใช้ `macos-latest` | +| `blacksmith-12vcpu-macos-latest` | `macos-swift` บน `openclaw/openclaw`; คลังที่แยกสำเนาจะย้อนกลับไปใช้ `macos-latest` | -## สิ่งเทียบเท่าในเครื่อง +## คำสั่งเทียบเท่าในเครื่อง ```bash pnpm changed:lanes # inspect the local changed-lane classifier for origin/main...HEAD @@ -135,9 +135,9 @@ pnpm test:perf:groups:compare .artifacts/test-perf/baseline-before.json .artifac pnpm perf:kova:summary --report .artifacts/kova/reports/mock-provider/report.json --output .artifacts/kova/summary.md ``` -## ประสิทธิภาพ OpenClaw +## ประสิทธิภาพของ OpenClaw -`OpenClaw Performance` คือ workflow ประสิทธิภาพของผลิตภัณฑ์/รันไทม์ โดยรันทุกวันบน `main` และสามารถ dispatch แบบแมนนวลได้: +`OpenClaw Performance` คือเวิร์กโฟลว์ประสิทธิภาพของผลิตภัณฑ์/รันไทม์ โดยรันทุกวันบน `main` และสามารถสั่งเรียกใช้ด้วยตนเองได้: ```bash gh workflow run openclaw-performance.yml --ref main -f profile=diagnostic -f repeat=3 @@ -145,27 +145,27 @@ gh workflow run openclaw-performance.yml --ref main -f profile=smoke -f repeat=1 gh workflow run openclaw-performance.yml --ref main -f target_ref=v2026.5.2 -f profile=diagnostic -f repeat=3 ``` -โดยปกติการ dispatch แบบแมนนวลจะ benchmark workflow ref ตั้งค่า `target_ref` เพื่อ benchmark release tag หรือ branch อื่นด้วย implementation ของ workflow ปัจจุบัน path ของรายงานที่เผยแพร่และ pointer ล่าสุดจะถูก key ตาม ref ที่ทดสอบ และ `index.md` แต่ละไฟล์จะบันทึก ref/SHA ที่ทดสอบ, workflow ref/SHA, Kova ref, profile, โหมด lane auth, model, จำนวน repeat และตัวกรอง scenario +การสั่งเรียกใช้ด้วยตนเองตามปกติจะวัดประสิทธิภาพของตัวอ้างอิงเวิร์กโฟลว์ ตั้งค่า `target_ref` เพื่อวัดประสิทธิภาพแท็กรีลีสหรือสาขาอื่นด้วยการใช้งานเวิร์กโฟลว์ปัจจุบัน พาธรายงานที่เผยแพร่และตัวชี้ล่าสุดใช้ตัวอ้างอิงที่ทดสอบเป็นคีย์ และ `index.md` แต่ละไฟล์จะบันทึกตัวอ้างอิง/SHA ที่ทดสอบ, ตัวอ้างอิง/SHA ของเวิร์กโฟลว์, ตัวอ้างอิง Kova, โปรไฟล์, โหมดการยืนยันตัวตนของเลน, โมเดล, จำนวนการทำซ้ำ, และตัวกรองสถานการณ์ -workflow จะติดตั้ง OCM จาก release ที่ pin ไว้ และ Kova จาก `openclaw/Kova` ที่อินพุต `kova_ref` ซึ่ง pin ไว้ จากนั้นรันสาม lane: +เวิร์กโฟลว์ติดตั้ง OCM จากรีลีสที่ปักหมุดไว้ และ Kova จาก `openclaw/Kova` ที่อินพุต `kova_ref` ที่ปักหมุดไว้ จากนั้นรันสามเลน: -- `mock-provider`: scenario การวินิจฉัยของ Kova กับรันไทม์ที่ build ในเครื่อง พร้อม auth ปลอมที่เข้ากันได้กับ OpenAI แบบ deterministic -- `mock-deep-profile`: การทำ profile CPU/heap/trace สำหรับ hotspot ของ startup, gateway และ agent-turn -- `live-gpt54`: agent turn จริงของ OpenAI `openai/gpt-5.4` ข้ามเมื่อไม่มี `OPENAI_API_KEY` +- `mock-provider`: สถานการณ์วินิจฉัยของ Kova กับรันไทม์ที่สร้างในเครื่อง โดยใช้การยืนยันตัวตน OpenAI-compatible แบบปลอมที่กำหนดผลแน่นอน +- `mock-deep-profile`: การทำโปรไฟล์ CPU/heap/trace สำหรับจุดที่ใช้ทรัพยากรสูงของการเริ่มต้น, Gateway, และเทิร์นของเอเจนต์ +- `live-gpt54`: เทิร์นของเอเจนต์ OpenAI จริงด้วย `openai/gpt-5.4` ซึ่งจะถูกข้ามเมื่อ `OPENAI_API_KEY` ไม่มีให้ใช้ -lane mock-provider ยังรัน source probe แบบ native ของ OpenClaw หลังจาก Kova pass: เวลา boot และหน่วยความจำของ gateway ในกรณี startup แบบ default, hook และ 50-Plugin; loop hello ซ้ำของ mock-OpenAI `channel-chat-baseline`; และคำสั่ง startup ของ CLI กับ gateway ที่ boot แล้ว สรุป Markdown ของ source probe อยู่ที่ `source/index.md` ในชุดรายงาน โดยมี JSON ดิบอยู่ข้างกัน +เลน mock-provider ยังรันการตรวจสอบซอร์สที่เป็นเนทีฟของ OpenClaw หลังจากรอบ Kova: เวลาเริ่มทำงานและหน่วยความจำของ Gateway ในกรณีเริ่มต้นแบบค่าเริ่มต้น, ฮุก, และ 50 Plugin; ลูป hello ของ OpenAI จำลอง `channel-chat-baseline` ซ้ำ ๆ; และคำสั่งเริ่มต้น CLI กับ Gateway ที่เริ่มทำงานแล้ว สรุป Markdown ของการตรวจสอบซอร์สอยู่ที่ `source/index.md` ในบันเดิลรายงาน พร้อม JSON ดิบที่อยู่ข้างกัน -ทุก lane จะอัปโหลด artifact ของ GitHub เมื่อมีการกำหนดค่า `CLAWGRIT_REPORTS_TOKEN` workflow จะ commit `report.json`, `report.md`, bundle, `index.md` และ artifact ของ source-probe ไปยัง `openclaw/clawgrit-reports` ใต้ `openclaw-performance//-//` ด้วย pointer ของ tested-ref ปัจจุบันจะถูกเขียนเป็น `openclaw-performance//latest-.json` +ทุกเลนอัปโหลดอาร์ติแฟกต์ GitHub เมื่อกำหนดค่า `CLAWGRIT_REPORTS_TOKEN` แล้ว เวิร์กโฟลว์ยังคอมมิต `report.json`, `report.md`, บันเดิล, `index.md`, และอาร์ติแฟกต์จากการตรวจสอบซอร์สเข้าไปใน `openclaw/clawgrit-reports` ใต้ `openclaw-performance//-//` ตัวชี้ตัวอ้างอิงที่ทดสอบล่าสุดจะถูกเขียนเป็น `openclaw-performance//latest-.json` -## การตรวจสอบความถูกต้องของการเผยแพร่เต็มรูปแบบ +## การตรวจสอบรีลีสแบบเต็ม -`Full Release Validation` คือ workflow umbrella แบบแมนนวลสำหรับ "รันทุกอย่างก่อนเผยแพร่" รับ branch, tag หรือ SHA ของ commit แบบเต็ม, dispatch workflow `CI` แบบแมนนวลพร้อม target นั้น, dispatch `Plugin Prerelease` สำหรับหลักฐาน plugin/package/static/Docker ที่ใช้เฉพาะการเผยแพร่ และ dispatch `OpenClaw Release Checks` สำหรับ install smoke, package acceptance, ชุดทดสอบ Docker release-path, live/E2E, OpenWebUI, QA Lab parity, Matrix และ lane Telegram เมื่อใช้ `rerun_group=all` และ `release_profile=full` จะรัน `NPM Telegram Beta E2E` กับ artifact `release-package-under-test` จาก release checks ด้วย หลังจากเผยแพร่แล้ว ให้ส่ง `npm_telegram_package_spec` เพื่อรัน lane package Telegram เดียวกันซ้ำกับ npm package ที่เผยแพร่แล้ว +`Full Release Validation` คือเวิร์กโฟลว์ครอบคลุมแบบ manual สำหรับ “รันทุกอย่างก่อนรีลีส” เวิร์กโฟลว์นี้รับสาขา แท็ก หรือ SHA ของคอมมิตแบบเต็ม, สั่งเรียกใช้เวิร์กโฟลว์ manual `CI` ด้วยเป้าหมายนั้น, สั่งเรียกใช้ `Plugin Prerelease` สำหรับหลักฐานเฉพาะรีลีสของ Plugin/แพ็กเกจ/static/Docker, และสั่งเรียกใช้ `OpenClaw Release Checks` สำหรับ smoke การติดตั้ง, การยอมรับแพ็กเกจ, ชุดเส้นทางรีลีสของ Docker, live/E2E, OpenWebUI, ความเท่าเทียมของ QA Lab, Matrix, และเลน Telegram เมื่อใช้ `rerun_group=all` และ `release_profile=full` เวิร์กโฟลว์นี้ยังรัน `NPM Telegram Beta E2E` กับอาร์ติแฟกต์ `release-package-under-test` จากการตรวจสอบรีลีสด้วย หลังเผยแพร่ ให้ส่ง `npm_telegram_package_spec` เพื่อรันเลนแพ็กเกจ Telegram เดิมซ้ำกับแพ็กเกจ npm ที่เผยแพร่แล้ว -ดู [การตรวจสอบความถูกต้องของการเผยแพร่เต็มรูปแบบ](/th/reference/full-release-validation) สำหรับ -เมทริกซ์ stage, ชื่องาน workflow ที่แน่นอน, ความแตกต่างของ profile, artifact และ -handle สำหรับ rerun แบบเจาะจง +ดู [การตรวจสอบรีลีสแบบเต็ม](/th/reference/full-release-validation) สำหรับ +เมทริกซ์ขั้นตอน, ชื่องานเวิร์กโฟลว์ที่แน่นอน, ความแตกต่างของโปรไฟล์, อาร์ติแฟกต์, และ +ตัวระบุสำหรับรันซ้ำแบบเจาะจง -`OpenClaw Release Publish` คือ workflow การเผยแพร่แบบแมนนวลที่ทำการเปลี่ยนแปลง Dispatch จาก `release/YYYY.M.D` หรือ `main` หลังจากมี release tag แล้ว และหลังจาก preflight ของ OpenClaw npm สำเร็จแล้ว โดยจะตรวจสอบ `pnpm plugins:sync:check`, dispatch `Plugin NPM Release` สำหรับ package Plugin ทั้งหมดที่เผยแพร่ได้, dispatch `Plugin ClawHub Release` สำหรับ SHA การเผยแพร่เดียวกัน และหลังจากนั้นเท่านั้นจึง dispatch `OpenClaw NPM Release` พร้อม `preflight_run_id` ที่บันทึกไว้ +`OpenClaw Release Publish` คือเวิร์กโฟลว์รีลีสแบบ manual ที่เปลี่ยนแปลงสถานะ สั่งเรียกใช้จาก `release/YYYY.M.D` หรือ `main` หลังจากแท็กรีลีสมีอยู่แล้ว และหลังจาก preflight ของ OpenClaw npm สำเร็จแล้ว เวิร์กโฟลว์นี้ตรวจสอบ `pnpm plugins:sync:check`, สั่งเรียกใช้ `Plugin NPM Release` สำหรับแพ็กเกจ Plugin ทั้งหมดที่เผยแพร่ได้, สั่งเรียกใช้ `Plugin ClawHub Release` สำหรับ SHA รีลีสเดียวกัน, แล้วจึงสั่งเรียกใช้ `OpenClaw NPM Release` พร้อม `preflight_run_id` ที่บันทึกไว้ ```bash gh workflow run openclaw-release-publish.yml \ @@ -175,40 +175,40 @@ gh workflow run openclaw-release-publish.yml \ -f npm_dist_tag=beta ``` -สำหรับหลักฐาน commit ที่ pin ไว้บน branch ที่เคลื่อนไหวเร็ว ให้ใช้ helper แทน +สำหรับหลักฐานคอมมิตที่ปักหมุดไว้บนสาขาที่เปลี่ยนเร็ว ให้ใช้ตัวช่วยแทน `gh workflow run ... --ref main -f ref=`: ```bash pnpm ci:full-release --sha ``` -dispatch ref ของ GitHub workflow ต้องเป็น branch หรือ tag ไม่ใช่ SHA ของ commit ดิบ helper จะ push branch ชั่วคราว `release-ci/-...` ที่ target SHA, dispatch `Full Release Validation` จาก ref ที่ pin นั้น, ตรวจสอบว่า `headSha` ของ workflow ลูกทุกตัวตรงกับ target และลบ branch ชั่วคราวเมื่อการรันเสร็จสิ้น ตัวตรวจสอบ umbrella จะ fail ด้วยหาก workflow ลูกใดรันที่ SHA อื่น +ตัวอ้างอิงสำหรับสั่งเรียกใช้เวิร์กโฟลว์ GitHub ต้องเป็นสาขาหรือแท็ก ไม่ใช่ SHA ของคอมมิตดิบ ตัวช่วยจะ push สาขาชั่วคราว `release-ci/-...` ที่ SHA เป้าหมาย, สั่งเรียกใช้ `Full Release Validation` จากตัวอ้างอิงที่ปักหมุดไว้นั้น, ตรวจสอบว่า `headSha` ของเวิร์กโฟลว์ลูกทุกตัวตรงกับเป้าหมาย, และลบสาขาชั่วคราวเมื่อการรันเสร็จสมบูรณ์ ตัวตรวจสอบเวิร์กโฟลว์ครอบคลุมจะล้มเหลวด้วยหากเวิร์กโฟลว์ลูกใดรันที่ SHA อื่น -`release_profile` ควบคุมขอบเขต live/provider ที่ส่งเข้าไปในการตรวจสอบรีลีส เวิร์กโฟลว์รีลีสแบบแมนนวลมีค่าเริ่มต้นเป็น `stable`; ใช้ `full` เฉพาะเมื่อคุณตั้งใจต้องการเมทริกซ์ provider/media สำหรับคำแนะนำแบบกว้างเท่านั้น +`release_profile` ควบคุมขอบเขต live/provider ที่ส่งเข้าไปในการตรวจสอบรุ่นเผยแพร่ เวิร์กโฟลว์รุ่นเผยแพร่แบบแมนนวลมีค่าเริ่มต้นเป็น `stable`; ใช้ `full` เฉพาะเมื่อคุณตั้งใจต้องการเมทริกซ์ผู้ให้บริการ/สื่อเชิงคำแนะนำที่กว้างเท่านั้น -- `minimum` คงไว้เฉพาะเลน OpenAI/core ที่สำคัญต่อรีลีสและเร็วที่สุด -- `stable` เพิ่มชุด provider/backend แบบ stable -- `full` รันเมทริกซ์ provider/media สำหรับคำแนะนำแบบกว้าง +- `minimum` คงไว้เฉพาะเลน OpenAI/core ที่สำคัญต่อรุ่นเผยแพร่และเร็วที่สุด +- `stable` เพิ่มชุดผู้ให้บริการ/แบ็กเอนด์ที่เสถียร +- `full` รันเมทริกซ์ผู้ให้บริการ/สื่อเชิงคำแนะนำที่กว้าง -umbrella จะบันทึก child run ids ที่ dispatch แล้ว และงานสุดท้าย `Verify full validation` จะตรวจสอบผลสรุปของ child run ปัจจุบันอีกครั้งและเพิ่มตารางงานที่ช้าที่สุดสำหรับแต่ละ child run หากมีการรัน child workflow ซ้ำและเปลี่ยนเป็นเขียว ให้รันซ้ำเฉพาะงาน parent verifier เพื่อรีเฟรชผลลัพธ์ของ umbrella และสรุปเวลา +งานครอบหลักจะบันทึก id ของการรันงานลูกที่ถูก dispatch และงานสุดท้าย `Verify full validation` จะตรวจสอบข้อสรุปปัจจุบันของการรันงานลูกอีกครั้ง และผนวกตารางงานที่ช้าที่สุดสำหรับการรันงานลูกแต่ละรายการ หากเวิร์กโฟลว์ลูกถูกรันใหม่แล้วเป็นสีเขียว ให้รันใหม่เฉพาะงานตัวตรวจสอบของงานหลักเพื่อรีเฟรชผลลัพธ์ของงานครอบหลักและสรุปเวลา -สำหรับการกู้คืน ทั้ง `Full Release Validation` และ `OpenClaw Release Checks` รับ `rerun_group` ใช้ `all` สำหรับ release candidate, `ci` สำหรับเฉพาะ child CI แบบเต็มตามปกติ, `plugin-prerelease` สำหรับเฉพาะ child prerelease ของ Plugin, `release-checks` สำหรับ child รีลีสทุกตัว หรือกลุ่มที่แคบกว่า: `install-smoke`, `cross-os`, `live-e2e`, `package`, `qa`, `qa-parity`, `qa-live`, หรือ `npm-telegram` บน umbrella วิธีนี้ทำให้การรันซ้ำของกล่องรีลีสที่ล้มเหลวถูกจำกัดขอบเขตหลังจากการแก้ไขแบบเจาะจง +สำหรับการกู้คืน ทั้ง `Full Release Validation` และ `OpenClaw Release Checks` รับ `rerun_group` ใช้ `all` สำหรับผู้สมัครรุ่นเผยแพร่, `ci` สำหรับงานลูก CI เต็มรูปแบบปกติเท่านั้น, `plugin-prerelease` สำหรับงานลูกก่อนเผยแพร่ของ Plugin เท่านั้น, `release-checks` สำหรับงานลูกของรุ่นเผยแพร่ทุกงาน หรือกลุ่มที่แคบกว่า: `install-smoke`, `cross-os`, `live-e2e`, `package`, `qa`, `qa-parity`, `qa-live` หรือ `npm-telegram` บนงานครอบหลัก วิธีนี้ทำให้การรันซ้ำของกล่องรุ่นเผยแพร่ที่ล้มเหลวมีขอบเขตจำกัดหลังจากการแก้ไขแบบเจาะจง -`OpenClaw Release Checks` ใช้ workflow ref ที่เชื่อถือได้เพื่อ resolve ref ที่เลือกหนึ่งครั้งเป็น tarball `release-package-under-test` จากนั้นส่ง artifact นั้นไปยังทั้งเวิร์กโฟลว์ Docker เส้นทางรีลีส live/E2E และ package acceptance shard วิธีนี้ทำให้ไบต์ของแพ็กเกจสอดคล้องกันข้ามกล่องรีลีส และหลีกเลี่ยงการ repack candidate เดียวกันใน child jobs หลายตัว +`OpenClaw Release Checks` ใช้ ref เวิร์กโฟลว์ที่เชื่อถือได้เพื่อ resolve ref ที่เลือกครั้งเดียวเป็น tarball `release-package-under-test` แล้วส่ง artifact นั้นต่อให้ทั้งเวิร์กโฟลว์ Docker เส้นทางรุ่นเผยแพร่ live/E2E และชาร์ด package acceptance วิธีนี้ทำให้ไบต์ของแพ็กเกจสอดคล้องกันในกล่องรุ่นเผยแพร่ต่างๆ และหลีกเลี่ยงการแพ็กผู้สมัครเดิมซ้ำในงานลูกหลายงาน การรัน `Full Release Validation` ซ้ำสำหรับ `ref=main` และ `rerun_group=all` -จะแทนที่ umbrella เก่า parent monitor จะยกเลิก child workflow ใด ๆ ที่ -dispatch ไปแล้วเมื่อ parent ถูกยกเลิก ดังนั้นการตรวจสอบ main ที่ใหม่กว่า -จะไม่ต้องรออยู่หลัง release-check run เก่าสองชั่วโมง การตรวจสอบ release branch/tag -และกลุ่ม rerun แบบเจาะจงจะคง `cancel-in-progress: false` +จะแทนที่งานครอบหลักที่เก่ากว่า ตัวติดตามของงานหลักจะยกเลิกเวิร์กโฟลว์ลูกใดๆ ที่ +ได้ dispatch ไปแล้วเมื่อถูกยกเลิกงานหลัก ดังนั้นการตรวจสอบ main ที่ใหม่กว่า +จะไม่ต้องค้างอยู่หลังการรัน release-check ที่ล้าสมัยนานสองชั่วโมง การตรวจสอบ branch/tag +ของรุ่นเผยแพร่และกลุ่มรันซ้ำแบบเจาะจงจะคง `cancel-in-progress: false` ไว้ ## ชาร์ด Live และ E2E -child ของ release live/E2E ยังคงครอบคลุม `pnpm test:live` แบบ native กว้าง แต่รันเป็นชาร์ดที่มีชื่อผ่าน `scripts/test-live-shard.mjs` แทน job แบบ serial หนึ่งงาน: +งานลูก release live/E2E ยังคงมีความครอบคลุม native `pnpm test:live` ที่กว้าง แต่รันเป็นชาร์ดที่มีชื่อผ่าน `scripts/test-live-shard.mjs` แทนที่จะเป็นงานแบบอนุกรมงานเดียว: - `native-live-src-agents` - `native-live-src-gateway-core` -- job `native-live-src-gateway-profiles` ที่กรองตาม provider +- งาน `native-live-src-gateway-profiles` ที่กรองตามผู้ให้บริการ - `native-live-src-gateway-backends` - `native-live-test` - `native-live-extensions-a-k` @@ -216,61 +216,61 @@ child ของ release live/E2E ยังคงครอบคลุม `pnpm t - `native-live-extensions-openai` - `native-live-extensions-o-z-other` - `native-live-extensions-xai` -- ชาร์ด media audio/video ที่แยกออก และชาร์ด music ที่กรองตาม provider +- ชาร์ดสื่อเสียง/วิดีโอที่แยกกัน และชาร์ดเพลงที่กรองตามผู้ให้บริการ -วิธีนี้คงการครอบคลุมไฟล์เดิมไว้ ในขณะเดียวกันก็ทำให้ความล้มเหลวของ provider live ที่ช้ารันซ้ำและวินิจฉัยได้ง่ายขึ้น ชื่อชาร์ดรวม `native-live-extensions-o-z`, `native-live-extensions-media`, และ `native-live-extensions-media-music` ยังคงใช้ได้สำหรับการรันซ้ำแบบ manual one-shot +วิธีนี้ยังคงความครอบคลุมไฟล์เดิมไว้ พร้อมทำให้ความล้มเหลวของผู้ให้บริการ live ที่ช้าง่ายต่อการรันซ้ำและวินิจฉัย ชื่อชาร์ดรวม `native-live-extensions-o-z`, `native-live-extensions-media` และ `native-live-extensions-media-music` ยังคงใช้ได้สำหรับการรันซ้ำแบบแมนนวลครั้งเดียว -ชาร์ด native live media รันใน `ghcr.io/openclaw/openclaw-live-media-runner:ubuntu-24.04` ซึ่งสร้างโดยเวิร์กโฟลว์ `Live Media Runner Image` อิมเมจนั้นติดตั้ง `ffmpeg` และ `ffprobe` ไว้ล่วงหน้าแล้ว; งาน media ตรวจสอบเฉพาะไบนารีก่อน setup เท่านั้น ให้คงชุดทดสอบ live ที่ใช้ Docker-backed ไว้บน Blacksmith runners ปกติ เพราะ container jobs ไม่ใช่ที่ที่เหมาะสำหรับเปิดการทดสอบ Docker ซ้อน +ชาร์ด native live media รันใน `ghcr.io/openclaw/openclaw-live-media-runner:ubuntu-24.04` ซึ่งสร้างโดยเวิร์กโฟลว์ `Live Media Runner Image` อิมเมจนั้นติดตั้ง `ffmpeg` และ `ffprobe` ไว้ล่วงหน้า งานสื่อจะตรวจสอบเฉพาะไบนารีก่อนตั้งค่าเท่านั้น ให้คงชุดทดสอบ live ที่ใช้ Docker ไว้บน runner Blacksmith ปกติ งานแบบ container ไม่ใช่ที่เหมาะสำหรับเริ่มการทดสอบ Docker ซ้อน -ชาร์ด live model/backend ที่ใช้ Docker-backed ใช้อิมเมจแชร์แยก `ghcr.io/openclaw/openclaw-live-test:` ต่อ commit ที่เลือกหนึ่งรายการ เวิร์กโฟลว์ live release จะ build และ push อิมเมจนั้นหนึ่งครั้ง จากนั้นชาร์ด Docker live model, Gateway ที่แบ่งตาม provider, CLI backend, ACP bind, และ Codex harness จะรันด้วย `OPENCLAW_SKIP_DOCKER_BUILD=1` ชาร์ด Gateway Docker มีขีดจำกัด `timeout` ระดับสคริปต์ที่ชัดเจนซึ่งต่ำกว่า timeout ของ workflow job เพื่อให้ container หรือเส้นทาง cleanup ที่ค้างล้มเหลวได้เร็ว แทนที่จะกินงบเวลา release-check ทั้งหมด หากชาร์ดเหล่านั้น rebuild target Docker source เต็มเองแยกกัน แสดงว่า release run ตั้งค่าผิดและจะเสียเวลาจริงไปกับการ build อิมเมจซ้ำ +ชาร์ดโมเดล/แบ็กเอนด์ live ที่ใช้ Docker ใช้อิมเมจที่ใช้ร่วมกันแยกต่างหาก `ghcr.io/openclaw/openclaw-live-test:` ต่อ commit ที่เลือกหนึ่งรายการ เวิร์กโฟลว์ release live จะสร้างและ push อิมเมจนั้นครั้งเดียว จากนั้นชาร์ดโมเดล Docker live, Gateway ที่แบ่งตามผู้ให้บริการ, แบ็กเอนด์ CLI, ACP bind และ harness ของ Codex จะรันด้วย `OPENCLAW_SKIP_DOCKER_BUILD=1` ชาร์ด Gateway Docker มีขีดจำกัด `timeout` ระดับสคริปต์ที่ชัดเจนต่ำกว่า timeout ของงานเวิร์กโฟลว์ เพื่อให้ container ที่ค้างหรือเส้นทาง cleanup ล้มเหลวเร็ว แทนที่จะใช้เวลางบ release-check ทั้งหมด หากชาร์ดเหล่านั้นสร้างเป้าหมาย Docker ซอร์สเต็มใหม่เองอย่างอิสระ แสดงว่าการรันรุ่นเผยแพร่ถูกตั้งค่าผิดและจะสิ้นเปลืองเวลานาฬิกาจริงกับการสร้างอิมเมจซ้ำ -## การยอมรับแพ็กเกจ +## Package Acceptance -ใช้ `Package Acceptance` เมื่อคำถามคือ "แพ็กเกจ OpenClaw ที่ติดตั้งได้นี้ทำงานเป็นผลิตภัณฑ์ได้หรือไม่" สิ่งนี้ต่างจาก CI ปกติ: CI ปกติตรวจสอบ source tree ขณะที่ package acceptance ตรวจสอบ tarball เดียวผ่าน Docker E2E harness เดียวกับที่ผู้ใช้ใช้งานหลัง install หรือ update +ใช้ `Package Acceptance` เมื่อคำถามคือ "แพ็กเกจ OpenClaw ที่ติดตั้งได้นี้ทำงานเป็นผลิตภัณฑ์ได้หรือไม่" สิ่งนี้แตกต่างจาก CI ปกติ: CI ปกติตรวจสอบ source tree ส่วน package acceptance ตรวจสอบ tarball เดียวผ่าน harness Docker E2E เดียวกับที่ผู้ใช้ใช้งานหลังติดตั้งหรืออัปเดต ### งาน -1. `resolve_package` checkout `workflow_ref`, resolve package candidate หนึ่งรายการ, เขียน `.artifacts/docker-e2e-package/openclaw-current.tgz`, เขียน `.artifacts/docker-e2e-package/package-candidate.json`, อัปโหลดทั้งคู่เป็น artifact `package-under-test`, และพิมพ์ source, workflow ref, package ref, version, SHA-256, และ profile ในสรุปขั้นตอนของ GitHub -2. `docker_acceptance` เรียก `openclaw-live-and-e2e-checks-reusable.yml` ด้วย `ref=workflow_ref` และ `package_artifact_name=package-under-test` เวิร์กโฟลว์ reusable จะดาวน์โหลด artifact นั้น, ตรวจสอบ inventory ของ tarball, เตรียม package-digest Docker images เมื่อจำเป็น, และรัน Docker lanes ที่เลือกกับแพ็กเกจนั้นแทนการ pack workflow checkout เมื่อ profile เลือก `docker_lanes` แบบเจาะจงหลายรายการ เวิร์กโฟลว์ reusable จะเตรียมแพ็กเกจและ shared images หนึ่งครั้ง จากนั้น fan out lanes เหล่านั้นเป็นงาน Docker แบบเจาะจงที่รันขนานกันพร้อม artifacts ที่ไม่ซ้ำกัน -3. `package_telegram` เรียก `NPM Telegram Beta E2E` ตามตัวเลือก โดยจะรันเมื่อ `telegram_mode` ไม่ใช่ `none` และติดตั้ง artifact `package-under-test` เดียวกันเมื่อ Package Acceptance resolve มาแล้ว; การ dispatch Telegram แบบ standalone ยังคงติดตั้ง npm spec ที่เผยแพร่แล้วได้ -4. `summary` ทำให้เวิร์กโฟลว์ล้มเหลวหาก package resolution, Docker acceptance, หรือ Telegram lane ตามตัวเลือกล้มเหลว +1. `resolve_package` checkout `workflow_ref`, resolve ผู้สมัครแพ็กเกจหนึ่งรายการ, เขียน `.artifacts/docker-e2e-package/openclaw-current.tgz`, เขียน `.artifacts/docker-e2e-package/package-candidate.json`, อัปโหลดทั้งสองอย่างเป็น artifact `package-under-test` และพิมพ์ source, workflow ref, package ref, เวอร์ชัน, SHA-256 และโปรไฟล์ในสรุปขั้นตอนของ GitHub +2. `docker_acceptance` เรียก `openclaw-live-and-e2e-checks-reusable.yml` ด้วย `ref=workflow_ref` และ `package_artifact_name=package-under-test` เวิร์กโฟลว์ที่ใช้ซ้ำจะดาวน์โหลด artifact นั้น ตรวจสอบ inventory ของ tarball เตรียมอิมเมจ Docker ที่อิง digest ของแพ็กเกจเมื่อจำเป็น และรันเลน Docker ที่เลือกกับแพ็กเกจนั้นแทนการแพ็ก workflow checkout เมื่อโปรไฟล์เลือก `docker_lanes` แบบเจาะจงหลายเลน เวิร์กโฟลว์ที่ใช้ซ้ำจะเตรียมแพ็กเกจและอิมเมจที่ใช้ร่วมกันครั้งเดียว แล้วกระจายเลนเหล่านั้นออกเป็นงาน Docker แบบเจาะจงที่รันขนานพร้อม artifact ที่ไม่ซ้ำกัน +3. `package_telegram` เลือกเรียก `NPM Telegram Beta E2E` งานนี้รันเมื่อ `telegram_mode` ไม่ใช่ `none` และติดตั้ง artifact `package-under-test` เดียวกันเมื่อ Package Acceptance resolve แล้ว ส่วนการ dispatch Telegram แบบ standalone ยังสามารถติดตั้งสเปก npm ที่เผยแพร่แล้วได้ +4. `summary` ทำให้เวิร์กโฟลว์ล้มเหลวหากการ resolve แพ็กเกจ, Docker acceptance หรือเลน Telegram แบบไม่บังคับล้มเหลว -### แหล่งที่มาของ Candidate +### แหล่งที่มาของผู้สมัคร -- `source=npm` รับเฉพาะ `openclaw@beta`, `openclaw@latest`, หรือเวอร์ชันรีลีส OpenClaw แบบ exact เช่น `openclaw@2026.4.27-beta.2` ใช้สิ่งนี้สำหรับ acceptance ของ prerelease/stable ที่เผยแพร่แล้ว -- `source=ref` pack branch, tag, หรือ full commit SHA ของ `package_ref` ที่เชื่อถือได้ resolver จะ fetch branch/tag ของ OpenClaw, ตรวจสอบว่า commit ที่เลือก reachable จากประวัติ branch ของ repository หรือ release tag, ติดตั้ง deps ใน detached worktree, และ pack ด้วย `scripts/package-openclaw-for-docker.mjs` -- `source=url` ดาวน์โหลด `.tgz` แบบ HTTPS; ต้องมี `package_sha256` -- `source=artifact` ดาวน์โหลด `.tgz` หนึ่งไฟล์จาก `artifact_run_id` และ `artifact_name`; `package_sha256` เป็นตัวเลือก แต่ควรระบุสำหรับ artifacts ที่แชร์ภายนอก +- `source=npm` รับเฉพาะ `openclaw@beta`, `openclaw@latest` หรือเวอร์ชันรุ่นเผยแพร่ OpenClaw ที่เจาะจง เช่น `openclaw@2026.4.27-beta.2` ใช้สิ่งนี้สำหรับ acceptance ของ prerelease/stable ที่เผยแพร่แล้ว +- `source=ref` แพ็ก branch, tag หรือ commit SHA เต็มของ `package_ref` ที่เชื่อถือได้ ตัว resolver จะ fetch branch/tag ของ OpenClaw, ตรวจสอบว่า commit ที่เลือกเข้าถึงได้จากประวัติ branch ของ repository หรือ tag รุ่นเผยแพร่, ติดตั้ง deps ใน worktree แบบ detached และแพ็กด้วย `scripts/package-openclaw-for-docker.mjs` +- `source=url` ดาวน์โหลด HTTPS `.tgz`; ต้องมี `package_sha256` +- `source=artifact` ดาวน์โหลด `.tgz` หนึ่งไฟล์จาก `artifact_run_id` และ `artifact_name`; `package_sha256` เป็นค่าทางเลือกแต่ควรระบุสำหรับ artifact ที่แชร์ภายนอก -แยก `workflow_ref` และ `package_ref` ออกจากกัน `workflow_ref` คือโค้ด workflow/harness ที่เชื่อถือได้ซึ่งรันการทดสอบ `package_ref` คือ source commit ที่จะถูก pack เมื่อ `source=ref` วิธีนี้ทำให้ test harness ปัจจุบันตรวจสอบ source commits เก่าที่เชื่อถือได้โดยไม่ต้องรัน workflow logic เก่า +แยก `workflow_ref` และ `package_ref` ออกจากกัน `workflow_ref` คือโค้ดเวิร์กโฟลว์/harness ที่เชื่อถือได้ซึ่งรันการทดสอบ `package_ref` คือ source commit ที่ถูกแพ็กเมื่อ `source=ref` วิธีนี้ทำให้ harness ทดสอบปัจจุบันตรวจสอบ source commit เก่าที่เชื่อถือได้โดยไม่ต้องรันตรรกะเวิร์กโฟลว์เก่า -### Suite profiles +### โปรไฟล์ชุดทดสอบ - `smoke` — `npm-onboard-channel-agent`, `gateway-network`, `config-reload` - `package` — `npm-onboard-channel-agent`, `doctor-switch`, `update-channel-switch`, `upgrade-survivor`, `published-upgrade-survivor`, `plugins-offline`, `plugin-update` -- `product` — `package` รวมกับ `mcp-channels`, `cron-mcp-cleanup`, `openai-web-search-minimal`, `openwebui` -- `full` — ชิ้นส่วน Docker เส้นทางรีลีสเต็มพร้อม OpenWebUI -- `custom` — `docker_lanes` แบบ exact; จำเป็นเมื่อ `suite_profile=custom` +- `product` — `package` พร้อม `mcp-channels`, `cron-mcp-cleanup`, `openai-web-search-minimal`, `openwebui` +- `full` — ชังก์เส้นทางรุ่นเผยแพร่ Docker เต็มรูปแบบพร้อม OpenWebUI +- `custom` — `docker_lanes` แบบตรงตัว; จำเป็นเมื่อ `suite_profile=custom` -profile `package` ใช้การครอบคลุม Plugin แบบ offline เพื่อให้การตรวจสอบแพ็กเกจที่เผยแพร่แล้วไม่ถูกกั้นด้วยความพร้อมใช้งาน live ของ ClawHub lane Telegram ตามตัวเลือกใช้ artifact `package-under-test` ซ้ำใน `NPM Telegram Beta E2E` โดยคงเส้นทาง npm spec ที่เผยแพร่แล้วไว้สำหรับ standalone dispatches +โปรไฟล์ `package` ใช้ความครอบคลุม Plugin แบบออฟไลน์ เพื่อให้การตรวจสอบแพ็กเกจที่เผยแพร่แล้วไม่ขึ้นกับความพร้อมใช้งานของ ClawHub แบบ live เลน Telegram แบบไม่บังคับจะใช้ artifact `package-under-test` ซ้ำใน `NPM Telegram Beta E2E` โดยยังคงเส้นทางสเปก npm ที่เผยแพร่ไว้สำหรับการ dispatch แบบ standalone -สำหรับนโยบายเฉพาะด้านการทดสอบ update และ Plugin รวมถึงคำสั่ง local, -Docker lanes, input ของ Package Acceptance, ค่าเริ่มต้นของรีลีส, และการวิเคราะห์ความล้มเหลว, -ดู [การทดสอบ updates และ plugins](/th/help/testing-updates-plugins) +สำหรับนโยบายทดสอบการอัปเดตและ Plugin โดยเฉพาะ รวมถึงคำสั่งในเครื่อง +เลน Docker, อินพุต Package Acceptance, ค่าเริ่มต้นของรุ่นเผยแพร่ และการคัดแยกความล้มเหลว +ดู [การทดสอบการอัปเดตและ Plugin](/th/help/testing-updates-plugins) -Release checks เรียก Package Acceptance ด้วย `source=artifact`, artifact แพ็กเกจรีลีสที่เตรียมไว้, `suite_profile=custom`, `docker_lanes='doctor-switch update-channel-switch upgrade-survivor published-upgrade-survivor plugins-offline plugin-update'`, `published_upgrade_survivor_baselines=all-since-2026.4.23`, `published_upgrade_survivor_scenarios=reported-issues`, และ `telegram_mode=mock-openai` วิธีนี้ทำให้หลักฐาน package migration, update, การ cleanup dependency ของ stale-plugin, การ repair การติดตั้ง configured-plugin, Plugin แบบ offline, plugin-update, และ Telegram อยู่บน tarball แพ็กเกจที่ resolve เดียวกัน ตั้งค่า `package_acceptance_package_spec` บน Full Release Validation หรือ OpenClaw Release Checks เพื่อรันเมทริกซ์เดียวกันกับแพ็กเกจ npm ที่ส่งมอบแล้วแทน artifact ที่ build จาก SHA การตรวจสอบรีลีส Cross-OS ยังคงครอบคลุม onboarding, installer, และพฤติกรรมแพลตฟอร์มที่เฉพาะกับ OS; การตรวจสอบผลิตภัณฑ์ด้าน package/update ควรเริ่มจาก Package Acceptance lane Docker `published-upgrade-survivor` ตรวจสอบ baseline แพ็กเกจที่เผยแพร่แล้วหนึ่งรายการต่อการรัน ใน Package Acceptance tarball `package-under-test` ที่ resolve แล้วจะเป็น candidate เสมอ และ `published_upgrade_survivor_baseline` เลือก fallback baseline ที่เผยแพร่แล้ว โดยมีค่าเริ่มต้นเป็น `openclaw@latest`; คำสั่ง rerun ของ lane ที่ล้มเหลวจะรักษา baseline นั้นไว้ ตั้งค่า `published_upgrade_survivor_baselines=all-since-2026.4.23` เพื่อขยาย Full Release CI ครอบคลุมทุก stable npm release ตั้งแต่ `2026.4.23` ถึง `latest`; `release-history` ยังคงใช้ได้สำหรับการสุ่มตัวอย่างแบบ manual ที่กว้างขึ้นพร้อม anchor ก่อนวันที่เก่ากว่า ตั้งค่า `published_upgrade_survivor_scenarios=reported-issues` เพื่อขยาย baseline เดียวกันข้าม fixtures ที่มีรูปแบบคล้าย issue สำหรับ config ของ Feishu, ไฟล์ bootstrap/persona ที่ preserve ไว้, การติดตั้ง OpenClaw Plugin ที่ configure ไว้, tilde log paths, และ root dependency ของ legacy Plugin ที่ stale เวิร์กโฟลว์ `Update Migration` แยกต่างหากใช้ Docker lane `update-migration` พร้อม `all-since-2026.4.23` และ `plugin-deps-cleanup` เมื่อคำถามคือการ cleanup update ที่เผยแพร่แล้วแบบละเอียดครบถ้วน ไม่ใช่ขอบเขต Full Release CI ปกติ การรันรวมแบบ local สามารถส่ง package specs แบบ exact ด้วย `OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPECS`, คง lane เดียวด้วย `OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPEC` เช่น `openclaw@2026.4.15`, หรือตั้งค่า `OPENCLAW_UPGRADE_SURVIVOR_SCENARIOS` สำหรับเมทริกซ์ scenario lane ที่เผยแพร่แล้ว configure baseline ด้วยสูตรคำสั่ง `openclaw config set` ที่ฝังไว้, บันทึกขั้นตอนสูตรใน `summary.json`, และ probe `/healthz`, `/readyz`, รวมถึงสถานะ RPC หลัง Gateway start lane Windows packaged และ installer fresh ยังตรวจสอบด้วยว่าแพ็กเกจที่ติดตั้งแล้วสามารถ import browser-control override จาก raw absolute Windows path ได้ smoke agent-turn แบบ cross-OS ของ OpenAI มีค่าเริ่มต้นเป็น `OPENCLAW_CROSS_OS_OPENAI_MODEL` เมื่อตั้งค่าไว้ มิฉะนั้นเป็น `openai/gpt-5.4` ดังนั้นหลักฐาน install และ Gateway จะยังอยู่บนโมเดลทดสอบ GPT-5 พร้อมหลีกเลี่ยงค่าเริ่มต้น GPT-4.x +การตรวจสอบรุ่นเผยแพร่เรียก Package Acceptance ด้วย `source=artifact`, artifact แพ็กเกจรุ่นเผยแพร่ที่เตรียมไว้, `suite_profile=custom`, `docker_lanes='doctor-switch update-channel-switch upgrade-survivor published-upgrade-survivor plugins-offline plugin-update'`, `published_upgrade_survivor_baselines=all-since-2026.4.23`, `published_upgrade_survivor_scenarios=reported-issues` และ `telegram_mode=mock-openai` วิธีนี้ทำให้หลักฐานการย้ายแพ็กเกจ, การอัปเดต, การ cleanup dependency ของ Plugin ที่ล้าสมัย, การซ่อมการติดตั้ง Plugin ที่ตั้งค่าไว้, Plugin แบบออฟไลน์, การอัปเดต Plugin และ Telegram อยู่บน tarball แพ็กเกจที่ resolve แล้วตัวเดียวกัน ตั้งค่า `package_acceptance_package_spec` บน Full Release Validation หรือ OpenClaw Release Checks เพื่อรันเมทริกซ์เดียวกันนั้นกับแพ็กเกจ npm ที่ส่งมอบแล้วแทน artifact ที่สร้างจาก SHA การตรวจสอบรุ่นเผยแพร่ข้าม OS ยังคงครอบคลุม onboarding, installer และพฤติกรรมแพลตฟอร์มเฉพาะ OS การตรวจสอบผลิตภัณฑ์ด้านแพ็กเกจ/การอัปเดตควรเริ่มด้วย Package Acceptance เลน Docker `published-upgrade-survivor` ตรวจสอบ baseline แพ็กเกจที่เผยแพร่แล้วหนึ่งรายการต่อการรัน ใน Package Acceptance tarball `package-under-test` ที่ resolve แล้วจะเป็นผู้สมัครเสมอ และ `published_upgrade_survivor_baseline` จะเลือก baseline ที่เผยแพร่แล้วสำหรับ fallback โดยมีค่าเริ่มต้นเป็น `openclaw@latest`; คำสั่งรันซ้ำของเลนที่ล้มเหลวจะคง baseline นั้นไว้ ตั้งค่า `published_upgrade_survivor_baselines=all-since-2026.4.23` เพื่อขยาย Full Release CI ให้ครอบคลุมรุ่นเผยแพร่ npm ที่เสถียรทุกรุ่นตั้งแต่ `2026.4.23` จนถึง `latest`; `release-history` ยังคงพร้อมใช้งานสำหรับการสุ่มตัวอย่างที่กว้างกว่าด้วยตนเองโดยใช้ anchor ก่อนวันที่เก่า ตั้งค่า `published_upgrade_survivor_scenarios=reported-issues` เพื่อขยาย baseline เดียวกันให้ครอบคลุม fixture รูปแบบ issue สำหรับ config ของ Feishu, ไฟล์ bootstrap/persona ที่ถูกเก็บรักษา, การติดตั้ง OpenClaw Plugin ที่ตั้งค่าไว้, path log แบบ tilde และราก dependency ของ Plugin legacy ที่ล้าสมัย เวิร์กโฟลว์ `Update Migration` แยกต่างหากใช้เลน Docker `update-migration` พร้อม `all-since-2026.4.23` และ `plugin-deps-cleanup` เมื่อคำถามคือการ cleanup การอัปเดตที่เผยแพร่แล้วแบบครบถ้วน ไม่ใช่ขอบเขต Full Release CI ปกติ การรันรวมในเครื่องสามารถส่งสเปกแพ็กเกจแบบตรงตัวด้วย `OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPECS`, คงเลนเดียวด้วย `OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPEC` เช่น `openclaw@2026.4.15` หรือตั้งค่า `OPENCLAW_UPGRADE_SURVIVOR_SCENARIOS` สำหรับเมทริกซ์สถานการณ์ เลนที่เผยแพร่แล้วจะตั้งค่า baseline ด้วยสูตรคำสั่ง `openclaw config set` ที่ฝังไว้ บันทึกขั้นตอนสูตรใน `summary.json` และ probe `/healthz`, `/readyz` พร้อมสถานะ RPC หลังเริ่ม Gateway เลนแพ็กเกจ Windows และเลน fresh installer ยังตรวจสอบด้วยว่าแพ็กเกจที่ติดตั้งแล้วสามารถ import override ของ browser-control จาก path Windows แบบ absolute ดิบได้ smoke ของ OpenAI cross-OS agent-turn มีค่าเริ่มต้นเป็น `OPENCLAW_CROSS_OS_OPENAI_MODEL` เมื่อมีการตั้งค่า มิฉะนั้นเป็น `openai/gpt-5.4` เพื่อให้หลักฐานการติดตั้งและ Gateway อยู่บนโมเดลทดสอบ GPT-5 พร้อมหลีกเลี่ยงค่าเริ่มต้น GPT-4.x -### หน้าต่างความเข้ากันได้ของ Legacy +### หน้าต่างความเข้ากันได้แบบ Legacy -Package Acceptance มีหน้าต่างความเข้ากันได้กับ legacy แบบมีขอบเขตสำหรับแพ็กเกจที่เผยแพร่แล้ว แพ็กเกจถึง `2026.4.25` รวมถึง `2026.4.25-beta.*` อาจใช้เส้นทาง compatibility ได้: +Package Acceptance มีหน้าต่างความเข้ากันได้แบบ legacy ที่มีขอบเขตสำหรับแพ็กเกจที่เผยแพร่แล้ว แพ็กเกจจนถึง `2026.4.25` รวมถึง `2026.4.25-beta.*` อาจใช้เส้นทางความเข้ากันได้: - รายการ QA ส่วนตัวที่รู้จักใน `dist/postinstall-inventory.json` อาจชี้ไปยังไฟล์ที่ tarball ละไว้; -- `doctor-switch` อาจข้าม subcase persistence ของ `gateway install --wrapper` เมื่อแพ็กเกจไม่ expose flag นั้น; -- `update-channel-switch` อาจ prune `pnpm.patchedDependencies` ที่หายไปจาก fake git fixture ที่ได้จาก tarball และอาจ log `update.channel` ที่ persist แล้วแต่หายไป; -- smoke ของ Plugin อาจอ่านตำแหน่ง install-record แบบ legacy หรือยอมรับ marketplace install-record persistence ที่หายไป; -- `plugin-update` อาจอนุญาตการ migrate metadata ของ config ขณะที่ยังต้องการให้ install record และพฤติกรรม no-reinstall คงเดิม +- `doctor-switch` อาจข้ามกรณีย่อย persistence ของ `gateway install --wrapper` เมื่อแพ็กเกจไม่ได้เปิดเผย flag นั้น; +- `update-channel-switch` อาจ prune `pnpm.patchedDependencies` ที่ขาดหายจาก fixture git ปลอมที่ได้จาก tarball และอาจ log `update.channel` ที่ persist ไว้แล้วแต่หายไป; +- smoke ของ Plugin อาจอ่านตำแหน่ง install-record แบบ legacy หรือยอมรับ persistence ของ marketplace install-record ที่ขาดหาย; +- `plugin-update` อาจอนุญาตการย้าย metadata ของ config ขณะยังคงกำหนดให้ install record และพฤติกรรมไม่ติดตั้งซ้ำต้องไม่เปลี่ยนแปลง -แพ็กเกจ `2026.4.26` ที่เผยแพร่แล้วอาจเตือนสำหรับไฟล์ stamp ของ local build metadata ที่ถูกส่งไปแล้วด้วย แพ็กเกจที่ใหม่กว่านั้นต้องเป็นไปตามสัญญาสมัยใหม่; เงื่อนไขเดียวกันจะล้มเหลวแทนที่จะเตือนหรือข้าม +แพ็กเกจ `2026.4.26` ที่เผยแพร่แล้วอาจเตือนเกี่ยวกับไฟล์ stamp metadata ของบิลด์ในเครื่องที่ถูกส่งไปแล้วด้วย แพ็กเกจที่ใหม่กว่านี้ต้องเป็นไปตามสัญญาสมัยใหม่ เงื่อนไขเดียวกันจะล้มเหลวแทนที่จะเตือนหรือข้าม ### ตัวอย่าง @@ -313,110 +313,110 @@ gh workflow run package-acceptance.yml \ -f docker_lanes='install-e2e plugin-update' ``` -เมื่อดีบักการรัน package acceptance ที่ล้มเหลว ให้เริ่มที่สรุป `resolve_package` เพื่อยืนยันแหล่งที่มาของแพ็กเกจ เวอร์ชัน และ SHA-256 จากนั้นตรวจสอบ child run ของ `docker_acceptance` และ Docker artifacts ของมัน: `.artifacts/docker-tests/**/summary.json`, `failures.json`, บันทึก lane, phase timings และคำสั่ง rerun ควร rerun โปรไฟล์แพ็กเกจที่ล้มเหลวหรือ Docker lanes ที่ตรงกัน แทนการ rerun full release validation +เมื่อดีบักการรัน package acceptance ที่ล้มเหลว ให้เริ่มจากสรุป `resolve_package` เพื่อยืนยันแหล่งที่มาของแพ็กเกจ เวอร์ชัน และ SHA-256 จากนั้นตรวจสอบการรันย่อย `docker_acceptance` และอาร์ติแฟกต์ Docker ของการรันนั้น: `.artifacts/docker-tests/**/summary.json`, `failures.json`, บันทึก lane, เวลาของแต่ละเฟส และคำสั่ง rerun ควร rerun โปรไฟล์แพ็กเกจที่ล้มเหลวหรือ Docker lane ที่ตรงกัน แทนการ rerun release validation แบบเต็ม ## Install smoke -เวิร์กโฟลว์ `Install Smoke` แยกต่างหากใช้ scope script เดียวกันซ้ำผ่าน job `preflight` ของตัวเอง โดยแบ่ง smoke coverage ออกเป็น `run_fast_install_smoke` และ `run_full_install_smoke` +Workflow `Install Smoke` ที่แยกต่างหากใช้สคริปต์ scope เดียวกันซ้ำผ่าน job `preflight` ของตัวเอง โดยแบ่งความครอบคลุมของ smoke เป็น `run_fast_install_smoke` และ `run_full_install_smoke` -- **Fast path** ทำงานสำหรับ pull requests ที่แตะพื้นผิว Docker/แพ็กเกจ การเปลี่ยนแปลงแพ็กเกจ/manifest ของ Plugin ที่รวมมา หรือพื้นผิว core plugin/channel/gateway/Plugin SDK ที่งาน Docker smoke ใช้ทดสอบ การเปลี่ยนแปลง Plugin ที่รวมมาแบบ source-only การแก้ไขเฉพาะ test และการแก้ไขเฉพาะ docs จะไม่จอง Docker workers Fast path จะบิลด์อิมเมจ root Dockerfile หนึ่งครั้ง ตรวจสอบ CLI รัน smoke ของ agents delete shared-workspace CLI รัน container gateway-network e2e ตรวจสอบ build arg ของส่วนขยายที่รวมมา และรันโปรไฟล์ Docker ของ Plugin ที่รวมมาแบบมีขอบเขตภายใต้ command timeout รวม 240 วินาที (การรัน Docker ของแต่ละสถานการณ์ถูกจำกัดแยกกัน) -- **Full path** เก็บ QR package install และ installer Docker/update coverage ไว้สำหรับการรันตามกำหนดทุกคืน manual dispatches, workflow-call release checks และ pull requests ที่แตะพื้นผิว installer/package/Docker จริงๆ ใน full mode นั้น install-smoke จะเตรียมหรือใช้ซ้ำอิมเมจ target-SHA GHCR root Dockerfile smoke หนึ่งอิมเมจ จากนั้นรัน QR package install, root Dockerfile/gateway smokes, installer/update smokes และ Docker E2E ของ Plugin ที่รวมมาแบบ fast เป็นงานแยกกัน เพื่อให้งาน installer ไม่ต้องรอหลัง root image smokes +- **Fast path** ทำงานสำหรับ pull request ที่แตะพื้นผิว Docker/package, การเปลี่ยนแปลงแพ็กเกจ/manifest ของ Plugin ที่บันเดิลมา หรือพื้นผิว Plugin/channel/gateway/Plugin SDK แกนกลางที่ Docker smoke jobs ทดสอบ การเปลี่ยนแปลง Plugin ที่บันเดิลมาเฉพาะซอร์ส การแก้ไขเฉพาะเทสต์ และการแก้ไขเฉพาะเอกสารจะไม่จอง Docker workers Fast path จะ build อิมเมจ Dockerfile รากหนึ่งครั้ง ตรวจสอบ CLI รัน agents delete shared-workspace CLI smoke รัน container gateway-network e2e ตรวจสอบ build arg ของส่วนขยายที่บันเดิลมา และรันโปรไฟล์ Docker ของ bundled-plugin แบบจำกัด ภายใต้ timeout คำสั่งรวม 240 วินาที (Docker run ของแต่ละ scenario ถูกจำกัดแยกกัน) +- **Full path** เก็บการติดตั้ง QR package และความครอบคลุม Docker/update ของ installer สำหรับการรันตามกำหนดการทุกคืน, manual dispatch, workflow-call release checks และ pull request ที่แตะพื้นผิว installer/package/Docker จริงๆ ในโหมดเต็ม install-smoke จะเตรียมหรือใช้อิมเมจ smoke ของ GHCR root Dockerfile target-SHA หนึ่งอิมเมจซ้ำ จากนั้นรัน QR package install, root Dockerfile/gateway smokes, installer/update smokes และ fast bundled-plugin Docker E2E เป็น jobs แยกกัน เพื่อให้งาน installer ไม่ต้องรออยู่หลัง root image smokes -การ push ไปยัง `main` (รวมถึง merge commits) ไม่ได้บังคับใช้ full path; เมื่อ logic ของ changed-scope จะร้องขอ coverage แบบ full บนการ push เวิร์กโฟลว์จะคง fast Docker smoke ไว้และปล่อย full install smoke ให้ nightly หรือ release validation +การ push ไปยัง `main` (รวมถึง merge commits) จะไม่บังคับใช้ full path เมื่อ logic changed-scope ขอ full coverage บน push workflow จะคง fast Docker smoke ไว้ และปล่อย full install smoke ให้ nightly หรือ release validation -smoke ของ Bun global install image-provider ที่ช้านั้นถูก gate แยกต่างหากด้วย `run_bun_global_install_smoke` โดยรันตามกำหนด nightly และจากเวิร์กโฟลว์ release checks และ manual `Install Smoke` dispatches สามารถเลือกเปิดใช้ได้ แต่ pull requests และการ push ไปยัง `main` จะไม่รัน QR และ installer Docker tests ยังคงมี Dockerfiles ที่เน้น install ของตัวเอง +slow Bun global install image-provider smoke ถูก gate แยกด้วย `run_bun_global_install_smoke` โดยรันตามตาราง nightly และจาก workflow release checks และ manual `Install Smoke` dispatch สามารถเลือกเปิดใช้ได้ แต่ pull request และ push ไปยัง `main` จะไม่รัน QR และ installer Docker tests ยังคงใช้ Dockerfiles ที่เน้นการติดตั้งของตัวเอง ## Local Docker E2E -`pnpm test:docker:all` จะ prebuild อิมเมจ live-test ที่ใช้ร่วมกันหนึ่งอิมเมจ แพ็ก OpenClaw หนึ่งครั้งเป็น npm tarball และบิลด์อิมเมจ `scripts/e2e/Dockerfile` ที่ใช้ร่วมกันสองอิมเมจ: +`pnpm test:docker:all` prebuild อิมเมจ live-test ที่ใช้ร่วมกันหนึ่งอิมเมจ แพ็ก OpenClaw หนึ่งครั้งเป็น npm tarball และ build อิมเมจ `scripts/e2e/Dockerfile` ที่ใช้ร่วมกันสองอิมเมจ: -- bare Node/Git runner สำหรับ lanes installer/update/plugin-dependency; -- อิมเมจเชิงฟังก์ชันที่ติดตั้ง tarball เดียวกันลงใน `/app` สำหรับ lanes ฟังก์ชันปกติ +- runner Node/Git เปล่าสำหรับ installer/update/plugin-dependency lanes; +- อิมเมจ functional ที่ติดตั้ง tarball เดียวกันลงใน `/app` สำหรับ functionality lanes ปกติ -คำจำกัดความของ Docker lane อยู่ใน `scripts/lib/docker-e2e-scenarios.mjs`, logic ของ planner อยู่ใน `scripts/lib/docker-e2e-plan.mjs` และ runner จะ execute เฉพาะ plan ที่เลือก scheduler เลือกอิมเมจต่อ lane ด้วย `OPENCLAW_DOCKER_E2E_BARE_IMAGE` และ `OPENCLAW_DOCKER_E2E_FUNCTIONAL_IMAGE` จากนั้นรัน lanes ด้วย `OPENCLAW_SKIP_DOCKER_BUILD=1` +นิยาม Docker lane อยู่ใน `scripts/lib/docker-e2e-scenarios.mjs`, planner logic อยู่ใน `scripts/lib/docker-e2e-plan.mjs` และ runner จะ execute เฉพาะ plan ที่เลือกเท่านั้น scheduler เลือกอิมเมจต่อ lane ด้วย `OPENCLAW_DOCKER_E2E_BARE_IMAGE` และ `OPENCLAW_DOCKER_E2E_FUNCTIONAL_IMAGE` จากนั้นรัน lanes ด้วย `OPENCLAW_SKIP_DOCKER_BUILD=1` -### ค่าที่ปรับได้ +### Tunables -| ตัวแปร | ค่าเริ่มต้น | วัตถุประสงค์ | +| Variable | Default | Purpose | | -------------------------------------- | ------- | --------------------------------------------------------------------------------------------- | -| `OPENCLAW_DOCKER_ALL_PARALLELISM` | 10 | จำนวน slot ของ main-pool สำหรับ lanes ปกติ | -| `OPENCLAW_DOCKER_ALL_TAIL_PARALLELISM` | 10 | จำนวน slot ของ tail-pool ที่ไวต่อ provider | -| `OPENCLAW_DOCKER_ALL_LIVE_LIMIT` | 9 | เพดาน live lane พร้อมกันเพื่อไม่ให้ providers throttle | -| `OPENCLAW_DOCKER_ALL_NPM_LIMIT` | 10 | เพดาน lane ติดตั้ง npm พร้อมกัน | -| `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT` | 7 | เพดาน multi-service lane พร้อมกัน | -| `OPENCLAW_DOCKER_ALL_START_STAGGER_MS` | 2000 | ระยะหน่วงระหว่างการเริ่ม lane เพื่อหลีกเลี่ยง Docker daemon create storms; ตั้ง `0` เพื่อไม่หน่วง | -| `OPENCLAW_DOCKER_ALL_LANE_TIMEOUT_MS` | 7200000 | fallback timeout ต่อ lane (120 นาที); live/tail lanes บางรายการใช้เพดานที่เข้มกว่า | -| `OPENCLAW_DOCKER_ALL_DRY_RUN` | unset | `1` พิมพ์ scheduler plan โดยไม่รัน lanes | -| `OPENCLAW_DOCKER_ALL_LANES` | unset | รายการ lane ที่ตรงกันทุกตัวคั่นด้วย comma; ข้าม cleanup smoke เพื่อให้ agents ทำซ้ำ lane ที่ล้มเหลวหนึ่งรายการได้ | +| `OPENCLAW_DOCKER_ALL_PARALLELISM` | 10 | จำนวน slot ของ main-pool สำหรับ lanes ปกติ | +| `OPENCLAW_DOCKER_ALL_TAIL_PARALLELISM` | 10 | จำนวน slot ของ tail-pool ที่อ่อนไหวต่อ provider | +| `OPENCLAW_DOCKER_ALL_LIVE_LIMIT` | 9 | เพดาน live lane พร้อมกัน เพื่อไม่ให้ providers throttle | +| `OPENCLAW_DOCKER_ALL_NPM_LIMIT` | 10 | เพดาน lane การติดตั้ง npm พร้อมกัน | +| `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT` | 7 | เพดาน multi-service lane พร้อมกัน | +| `OPENCLAW_DOCKER_ALL_START_STAGGER_MS` | 2000 | หน่วงระหว่างการเริ่ม lane เพื่อหลีกเลี่ยง Docker daemon create storms; ตั้ง `0` เพื่อไม่หน่วง | +| `OPENCLAW_DOCKER_ALL_LANE_TIMEOUT_MS` | 7200000 | timeout สำรองต่อ lane (120 นาที); live/tail lanes ที่เลือกใช้เพดานที่เข้มกว่า | +| `OPENCLAW_DOCKER_ALL_DRY_RUN` | unset | `1` พิมพ์ scheduler plan โดยไม่รัน lanes | +| `OPENCLAW_DOCKER_ALL_LANES` | unset | รายการ lane แบบ exact คั่นด้วย comma; ข้าม cleanup smoke เพื่อให้ agents ทำซ้ำ lane ที่ล้มเหลวหนึ่ง lane ได้ | -lane ที่หนักกว่า effective cap ของตัวเองยังสามารถเริ่มจาก pool ที่ว่างได้ จากนั้นจะรันเพียงลำพังจนกว่าจะปล่อย capacity local aggregate จะ preflight Docker ลบคอนเทนเนอร์ OpenClaw E2E ที่ค้างอยู่ แสดงสถานะ active-lane บันทึก lane timings เพื่อจัดลำดับ longest-first และหยุด scheduling lanes แบบ pooled ใหม่หลังความล้มเหลวแรกตามค่าเริ่มต้น +lane ที่หนักกว่าเพดาน effective ของตัวเองยังสามารถเริ่มจาก pool ว่างได้ แล้วจะรันเพียงลำพังจนกว่าจะคืน capacity aggregate preflight ในเครื่องจะตรวจสอบ Docker, ลบคอนเทนเนอร์ OpenClaw E2E ที่ค้างอยู่, แสดงสถานะ active-lane, บันทึกเวลาของ lane เพื่อจัดลำดับ longest-first และตามค่าเริ่มต้นจะหยุด schedule pooled lanes ใหม่หลังพบ failure แรก -### เวิร์กโฟลว์ live/E2E ที่ใช้ซ้ำได้ +### Workflow live/E2E ที่นำกลับมาใช้ซ้ำได้ -เวิร์กโฟลว์ live/E2E ที่ใช้ซ้ำได้จะถาม `scripts/test-docker-all.mjs --plan-json` ว่าต้องใช้ coverage ของแพ็กเกจ ชนิดอิมเมจ live image, lane และ credentials ใด `scripts/docker-e2e.mjs` จากนั้นจะแปลง plan นั้นเป็น GitHub outputs และ summaries โดยจะ either แพ็ก OpenClaw ผ่าน `scripts/package-openclaw-for-docker.mjs`, ดาวน์โหลด package artifact ของ current-run หรือดาวน์โหลด package artifact จาก `package_artifact_run_id`; ตรวจสอบ inventory ของ tarball; บิลด์และ push อิมเมจ bare/functional GHCR Docker E2E ที่ tag ด้วย package-digest ผ่าน Docker layer cache ของ Blacksmith เมื่อ plan ต้องใช้ lanes ที่ติดตั้งแพ็กเกจแล้ว; และใช้ inputs `docker_e2e_bare_image`/`docker_e2e_functional_image` ที่ให้มา หรืออิมเมจ package-digest ที่มีอยู่ซ้ำแทนการ rebuild การ pull อิมเมจ Docker จะ retry ด้วย timeout ต่อ attempt แบบมีขอบเขต 180 วินาที เพื่อให้ registry/cache stream ที่ค้าง retry ได้เร็วแทนที่จะใช้เวลาส่วนใหญ่ของ CI critical path +Workflow live/E2E ที่นำกลับมาใช้ซ้ำได้จะถาม `scripts/test-docker-all.mjs --plan-json` ว่าต้องใช้แพ็กเกจ ชนิดอิมเมจ live image, lane และ credential coverage ใด จากนั้น `scripts/docker-e2e.mjs` จะแปลง plan นั้นเป็น GitHub outputs และ summaries โดยจะ pack OpenClaw ผ่าน `scripts/package-openclaw-for-docker.mjs`, ดาวน์โหลด package artifact ของ current-run หรือดาวน์โหลด package artifact จาก `package_artifact_run_id`; ตรวจสอบ inventory ของ tarball; build และ push อิมเมจ GHCR Docker E2E แบบ bare/functional ที่ tag ด้วย package digest ผ่าน Docker layer cache ของ Blacksmith เมื่อ plan ต้องใช้ lanes ที่ติดตั้งแพ็กเกจแล้ว; และใช้อินพุต `docker_e2e_bare_image`/`docker_e2e_functional_image` ที่ให้มา หรืออิมเมจ package-digest ที่มีอยู่แทนการ rebuild การ pull อิมเมจ Docker จะ retry ด้วย timeout ต่อ attempt แบบจำกัด 180 วินาที เพื่อให้ registry/cache stream ที่ค้าง retry ได้เร็ว แทนที่จะกินเวลาส่วนใหญ่ของ critical path ของ CI -### ชิ้นส่วน release-path +### Release-path chunks -Docker coverage ของ release จะรัน jobs แบบแบ่งเป็น chunk ที่เล็กลงด้วย `OPENCLAW_SKIP_DOCKER_BUILD=1` เพื่อให้แต่ละ chunk pull เฉพาะชนิดอิมเมจที่ต้องใช้และ execute หลาย lanes ผ่าน scheduler แบบ weighted เดียวกัน: +ความครอบคลุม Release Docker รัน jobs แบบ chunk ขนาดเล็กกว่าด้วย `OPENCLAW_SKIP_DOCKER_BUILD=1` เพื่อให้แต่ละ chunk pull เฉพาะชนิดอิมเมจที่ต้องใช้ และ execute หลาย lanes ผ่าน weighted scheduler เดียวกัน: - `OPENCLAW_DOCKER_ALL_PROFILE=release-path` - `OPENCLAW_DOCKER_ALL_CHUNK=core | package-update-openai | package-update-anthropic | package-update-core | plugins-runtime-plugins | plugins-runtime-services | plugins-runtime-install-a..h` -Docker chunks ของ release ปัจจุบันคือ `core`, `package-update-openai`, `package-update-anthropic`, `package-update-core`, `plugins-runtime-plugins`, `plugins-runtime-services` และ `plugins-runtime-install-a` ถึง `plugins-runtime-install-h` ส่วน `plugins-runtime-core`, `plugins-runtime` และ `plugins-integrations` ยังคงเป็น aliases รวมของ plugin/runtime alias ของ lane `install-e2e` ยังคงเป็น alias rerun แบบ manual รวมสำหรับ provider installer lanes ทั้งสอง +release Docker chunks ปัจจุบันคือ `core`, `package-update-openai`, `package-update-anthropic`, `package-update-core`, `plugins-runtime-plugins`, `plugins-runtime-services` และ `plugins-runtime-install-a` ถึง `plugins-runtime-install-h` ส่วน `plugins-runtime-core`, `plugins-runtime` และ `plugins-integrations` ยังคงเป็น alias รวมของ plugin/runtime alias lane `install-e2e` ยังคงเป็น alias rerun แบบ manual รวมสำหรับ provider installer lanes ทั้งสอง -OpenWebUI ถูกพับเข้าไปใน `plugins-runtime-services` เมื่อ full release-path coverage ร้องขอ และเก็บ chunk `openwebui` แบบ standalone ไว้เฉพาะ dispatches ที่เป็น OpenWebUI-only เท่านั้น bundled-channel update lanes จะ retry หนึ่งครั้งสำหรับความล้มเหลวชั่วคราวของเครือข่าย npm +OpenWebUI ถูกพับเข้าไปใน `plugins-runtime-services` เมื่อ full release-path coverage ขอ และคง chunk `openwebui` แบบ standalone ไว้เฉพาะสำหรับ dispatch ที่เป็น OpenWebUI-only lanes อัปเดต bundled-channel จะ retry หนึ่งครั้งสำหรับความล้มเหลวชั่วคราวของเครือข่าย npm -แต่ละ chunk จะอัปโหลด `.artifacts/docker-tests/` พร้อมบันทึก lane, timings, `summary.json`, `failures.json`, phase timings, scheduler plan JSON, ตาราง slow-lane และคำสั่ง rerun ต่อ lane input `docker_lanes` ของเวิร์กโฟลว์จะรัน lanes ที่เลือกกับอิมเมจที่เตรียมไว้แทน chunk jobs ซึ่งจำกัดการดีบัก failed-lane ให้อยู่ใน Docker job เป้าหมายหนึ่งรายการ และเตรียม ดาวน์โหลด หรือใช้ package artifact ซ้ำสำหรับการรันนั้น; หาก lane ที่เลือกเป็น live Docker lane งานเป้าหมายจะบิลด์ live-test image ในเครื่องสำหรับ rerun นั้น คำสั่ง GitHub rerun ต่อ lane ที่สร้างขึ้นจะรวม `package_artifact_run_id`, `package_artifact_name` และ prepared image inputs เมื่อมีค่าเหล่านั้น เพื่อให้ lane ที่ล้มเหลวสามารถใช้แพ็กเกจและอิมเมจเดียวกันจากการรันที่ล้มเหลวซ้ำได้ +แต่ละ chunk จะอัปโหลด `.artifacts/docker-tests/` พร้อม lane logs, timings, `summary.json`, `failures.json`, เวลาของแต่ละเฟส, scheduler plan JSON, ตาราง slow-lane และคำสั่ง rerun ต่อ lane อินพุต `docker_lanes` ของ workflow จะรัน lanes ที่เลือกกับอิมเมจที่เตรียมไว้แทน chunk jobs ซึ่งทำให้การดีบัก failed-lane ถูกจำกัดอยู่ใน Docker job เป้าหมายหนึ่ง job และเตรียม ดาวน์โหลด หรือใช้ package artifact ซ้ำสำหรับการรันนั้น หาก lane ที่เลือกเป็น live Docker lane job เป้าหมายจะ build อิมเมจ live-test ในเครื่องสำหรับ rerun นั้น คำสั่ง GitHub rerun ต่อ lane ที่สร้างขึ้นจะรวม `package_artifact_run_id`, `package_artifact_name` และอินพุตอิมเมจที่เตรียมไว้เมื่อมีค่าเหล่านั้น เพื่อให้ lane ที่ล้มเหลวสามารถใช้แพ็กเกจและอิมเมจ exact จากการรันที่ล้มเหลวซ้ำได้ ```bash pnpm test:docker:rerun # download Docker artifacts and print combined/per-lane targeted rerun commands pnpm test:docker:timings # slow-lane and phase critical-path summaries ``` -เวิร์กโฟลว์ live/E2E ตามกำหนดเวลาจะรัน Docker suite แบบ full release-path ทุกวัน +workflow live/E2E ตามกำหนดการจะรันชุด Docker release-path แบบเต็มทุกวัน ## Plugin Prerelease -`Plugin Prerelease` เป็น coverage ระดับ product/package ที่มีค่าใช้จ่ายสูงกว่า จึงเป็นเวิร์กโฟลว์แยกที่ถูก dispatch โดย `Full Release Validation` หรือโดย operator อย่างชัดเจน pull requests ปกติ การ push ไปยัง `main` และ standalone manual CI dispatches จะปิด suite นี้ไว้ โดยจะกระจาย tests ของ Plugin ที่รวมมาข้าม extension workers แปดตัว; งาน extension shard เหล่านั้นรัน plugin config groups ได้สูงสุดสองกลุ่มพร้อมกัน โดยใช้ Vitest worker หนึ่งตัวต่อกลุ่มและ Node heap ที่ใหญ่ขึ้น เพื่อให้ plugin batches ที่ import-heavy ไม่สร้าง CI jobs เพิ่ม เส้นทาง Docker prerelease เฉพาะ release จะ batch Docker lanes เป้าหมายเป็นกลุ่มเล็กๆ เพื่อหลีกเลี่ยงการจอง runners หลายสิบตัวสำหรับ jobs ความยาวหนึ่งถึงสามนาที +`Plugin Prerelease` เป็นความครอบคลุม product/package ที่มีต้นทุนสูงกว่า จึงเป็น workflow แยกที่ dispatch โดย `Full Release Validation` หรือโดย operator โดยชัดเจน pull request ปกติ, push ไปยัง `main` และ manual CI dispatch แบบ standalone จะปิด suite นั้นไว้ โดยจะบาลานซ์เทสต์ Plugin ที่บันเดิลมาใน extension workers แปดตัว; jobs shard ของส่วนขยายเหล่านั้นรันกลุ่ม config ของ Plugin ได้สูงสุดครั้งละสองกลุ่ม โดยใช้ Vitest worker หนึ่งตัวต่อกลุ่มและ Node heap ที่ใหญ่ขึ้น เพื่อให้ batch ของ Plugin ที่ import-heavy ไม่สร้าง CI jobs เพิ่มเติม path Docker prerelease สำหรับ release-only จะ batch Docker lanes เป้าหมายเป็นกลุ่มเล็ก เพื่อหลีกเลี่ยงการจอง runners จำนวนมากสำหรับ jobs ที่ใช้เวลาหนึ่งถึงสามนาที ## QA Lab -QA Lab มี CI lanes เฉพาะนอกเวิร์กโฟลว์ smart-scoped หลัก Agentic parity ถูกซ้อนอยู่ภายใต้ QA และ release harnesses แบบกว้าง ไม่ใช่เวิร์กโฟลว์ PR แบบ standalone ใช้ `Full Release Validation` พร้อม `rerun_group=qa-parity` เมื่อ parity ควรไปพร้อมกับการรัน validation แบบกว้าง +QA Lab มี CI lanes เฉพาะอยู่นอก workflow smart-scoped หลัก Agentic parity ถูกซ้อนอยู่ใต้ QA และ release harnesses แบบกว้าง ไม่ใช่ workflow PR แบบ standalone ใช้ `Full Release Validation` พร้อม `rerun_group=qa-parity` เมื่อควรให้ parity ไปกับการรัน validation แบบกว้าง -- เวิร์กโฟลว์ `QA-Lab - All Lanes` รันทุกคืนบน `main` และบน manual dispatch; โดย fan out mock parity lane, live Matrix lane และ live Telegram กับ Discord lanes เป็น jobs ขนานกัน Live jobs ใช้ environment `qa-live-shared` และ Telegram/Discord ใช้ Convex leases +- Workflow `QA-Lab - All Lanes` รันทุกคืนบน `main` และเมื่อ manual dispatch; โดยกระจาย mock parity lane, live Matrix lane และ live Telegram กับ Discord lanes เป็น jobs ขนานกัน Live jobs ใช้ environment `qa-live-shared` และ Telegram/Discord ใช้ Convex leases -Release checks รัน Matrix และ Telegram live transport lanes ด้วย deterministic mock provider และโมเดลแบบ mock-qualified (`mock-openai/gpt-5.5` และ `mock-openai/gpt-5.5-alt`) เพื่อแยก channel contract ออกจาก live model latency และการ startup ปกติของ provider-plugin live transport gateway ปิด memory search เพราะ QA parity ครอบคลุมพฤติกรรม memory แยกต่างหาก; provider connectivity ถูกครอบคลุมโดย live model, native provider และ Docker provider suites แยกต่างหาก +Release checks รัน Matrix และ Telegram live transport lanes ด้วย mock provider ที่กำหนดผลได้และ mock-qualified models (`mock-openai/gpt-5.5` และ `mock-openai/gpt-5.5-alt`) เพื่อแยก channel contract ออกจาก latency ของ live model และการเริ่มต้น provider-plugin ปกติ live transport gateway ปิด memory search เพราะ QA parity ครอบคลุมพฤติกรรม memory แยกต่างหาก; provider connectivity ถูกครอบคลุมโดยชุด live model, native provider และ Docker provider ที่แยกกัน -Matrix ใช้ `--profile fast` สำหรับ scheduled และ release gates และเพิ่ม `--fail-fast` เฉพาะเมื่อ CLI ที่ checkout รองรับ ค่าเริ่มต้นของ CLI และ manual workflow input ยังคงเป็น `all`; manual `matrix_profile=all` dispatch จะแบ่ง full Matrix coverage เป็น shard เสมอใน jobs `transport`, `media`, `e2ee-smoke`, `e2ee-deep` และ `e2ee-cli` +Matrix ใช้ `--profile fast` สำหรับ scheduled และ release gates โดยเพิ่ม `--fail-fast` เฉพาะเมื่อ CLI ที่ checkout รองรับ ค่าเริ่มต้นของ CLI และอินพุต manual workflow ยังคงเป็น `all`; manual `matrix_profile=all` dispatch จะแบ่ง full Matrix coverage เป็น jobs `transport`, `media`, `e2ee-smoke`, `e2ee-deep` และ `e2ee-cli` เสมอ -`OpenClaw Release Checks` ยังรัน QA Lab lanes ที่สำคัญต่อ release ก่อนอนุมัติ release; QA parity gate ของมันรัน candidate และ baseline packs เป็น parallel lane jobs จากนั้นดาวน์โหลด artifacts ทั้งสองลงใน report job ขนาดเล็กสำหรับการเปรียบเทียบ parity ขั้นสุดท้าย +`OpenClaw Release Checks` ยังรัน release-critical QA Lab lanes ก่อน release approval ด้วย; QA parity gate ของมันรัน candidate และ baseline packs เป็น lane jobs ขนานกัน จากนั้นดาวน์โหลด artifacts ทั้งสองเข้าไปใน report job ขนาดเล็กสำหรับการเปรียบเทียบ parity ขั้นสุดท้าย -สำหรับ PRs ปกติ ให้ยึดตามหลักฐาน CI/check ที่ scoped แทนการถือว่า parity เป็นสถานะที่จำเป็น +สำหรับ PR ปกติ ให้ตามหลักฐาน CI/check แบบ scoped แทนการถือว่า parity เป็นสถานะที่จำเป็น ## CodeQL -เวิร์กโฟลว์ `CodeQL` ตั้งใจให้เป็นตัวสแกนความปลอดภัยรอบแรกแบบแคบ ไม่ใช่การกวาดตรวจทั้ง repository แบบเต็ม รายวัน แบบสั่งเอง และ guard run ของ pull request ที่ไม่ใช่ draft จะสแกนโค้ดเวิร์กโฟลว์ Actions พร้อมพื้นผิว JavaScript/TypeScript ที่มีความเสี่ยงสูงสุด โดยใช้ security query ความเชื่อมั่นสูงที่กรองไว้ที่ `security-severity` ระดับสูง/วิกฤต +เวิร์กโฟลว์ `CodeQL` เป็นสแกนเนอร์ความปลอดภัยรอบแรกที่ตั้งใจให้มีขอบเขตแคบ ไม่ใช่การกวาดตรวจทั้งรีโพสิทอรีแบบเต็ม รายวัน แบบแมนนวล และการรัน guard สำหรับ pull request ที่ไม่ใช่ draft จะสแกนโค้ดเวิร์กโฟลว์ Actions รวมถึงพื้นผิว JavaScript/TypeScript ที่มีความเสี่ยงสูงที่สุด โดยใช้คิวรีความปลอดภัยความเชื่อมั่นสูงที่กรองไว้สำหรับ `security-severity` ระดับสูง/วิกฤต -guard ของ pull request ยังคงเบา: จะเริ่มเฉพาะเมื่อมีการเปลี่ยนแปลงภายใต้ `.github/actions`, `.github/codeql`, `.github/workflows`, `packages` หรือ `src` และจะรันเมทริกซ์ความปลอดภัยความเชื่อมั่นสูงชุดเดียวกับเวิร์กโฟลว์ตามกำหนด Android และ macOS CodeQL จะไม่อยู่ในค่าเริ่มต้นของ PR +pull request guard ยังคงเบา: จะเริ่มเฉพาะการเปลี่ยนแปลงภายใต้ `.github/actions`, `.github/codeql`, `.github/workflows`, `packages` หรือ `src` และรันเมทริกซ์ความปลอดภัยความเชื่อมั่นสูงชุดเดียวกับเวิร์กโฟลว์ตามกำหนดเวลา Android และ macOS CodeQL จะไม่อยู่ในค่าเริ่มต้นของ PR ### หมวดหมู่ความปลอดภัย -| หมวดหมู่ | พื้นผิว | +| หมวดหมู่ | พื้นผิว | | ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | -| `/codeql-security-high/core-auth-secrets` | การยืนยันตัวตน, secret, แซนด์บ็อกซ์, Cron และ baseline ของ Gateway | -| `/codeql-security-high/channel-runtime-boundary` | สัญญาการใช้งานของ implementation ช่องทางหลัก รวมถึง runtime ของช่องทาง Plugin, Gateway, Plugin SDK, secret และจุดสัมผัสด้าน audit | -| `/codeql-security-high/network-ssrf-boundary` | พื้นผิวนโยบาย SSRF ของ core SSRF, การแยกวิเคราะห์ IP, network guard, web-fetch และ Plugin SDK | -| `/codeql-security-high/mcp-process-tool-boundary` | เซิร์ฟเวอร์ MCP, helper การรัน process, การส่งออกขาออก และ gate การรันเครื่องมือของ agent | -| `/codeql-security-high/plugin-trust-boundary` | พื้นผิวความไว้วางใจของการติดตั้ง Plugin, loader, manifest, registry, การติดตั้ง package-manager, การโหลด source และสัญญา package ของ Plugin SDK | +| `/codeql-security-high/core-auth-secrets` | Auth, ความลับ, sandbox, cron และ Gateway baseline | +| `/codeql-security-high/channel-runtime-boundary` | สัญญาการทำงานของ core channel รวมถึง channel Plugin runtime, Gateway, Plugin SDK, ความลับ, จุดสัมผัส audit | +| `/codeql-security-high/network-ssrf-boundary` | Core SSRF, การแยกวิเคราะห์ IP, network guard, web-fetch และพื้นผิวนโยบาย SSRF ของ Plugin SDK | +| `/codeql-security-high/mcp-process-tool-boundary` | เซิร์ฟเวอร์ MCP, helper สำหรับการประมวลผลการรัน process, การส่งออกขาออก และ gate การรันเครื่องมือของ agent | +| `/codeql-security-high/plugin-trust-boundary` | การติดตั้ง Plugin, loader, manifest, registry, การติดตั้ง package-manager, source-loading และพื้นผิวความเชื่อถือของสัญญา package ของ Plugin SDK | ### shard ความปลอดภัยเฉพาะแพลตฟอร์ม -- `CodeQL Android Critical Security` — shard ความปลอดภัย Android ตามกำหนดเวลา สร้างแอป Android ด้วยตนเองสำหรับ CodeQL บน Blacksmith Linux runner ที่เล็กที่สุดที่ workflow sanity ยอมรับ อัปโหลดภายใต้ `/codeql-critical-security/android` -- `CodeQL macOS Critical Security` — shard ความปลอดภัย macOS รายสัปดาห์/สั่งเอง สร้างแอป macOS ด้วยตนเองสำหรับ CodeQL บน Blacksmith macOS กรองผลลัพธ์การ build ของ dependency ออกจาก SARIF ที่อัปโหลด และอัปโหลดภายใต้ `/codeql-critical-security/macos` คงไว้นอกค่าเริ่มต้นรายวันเพราะการ build macOS ครอง runtime แม้จะสะอาดก็ตาม +- `CodeQL Android Critical Security` — shard ความปลอดภัย Android ตามกำหนดเวลา สร้างแอป Android แบบแมนนวลสำหรับ CodeQL บน Blacksmith Linux runner ที่เล็กที่สุดที่ workflow sanity ยอมรับ อัปโหลดภายใต้ `/codeql-critical-security/android` +- `CodeQL macOS Critical Security` — shard ความปลอดภัย macOS แบบรายสัปดาห์/แมนนวล สร้างแอป macOS แบบแมนนวลสำหรับ CodeQL บน Blacksmith macOS กรองผลการสร้าง dependency ออกจาก SARIF ที่อัปโหลด และอัปโหลดภายใต้ `/codeql-critical-security/macos` เก็บไว้นอกค่าเริ่มต้นรายวันเพราะการสร้าง macOS ใช้ runtime มากที่สุดแม้เมื่อสะอาด -### หมวดหมู่ Critical Quality +### หมวดหมู่คุณภาพวิกฤต -`CodeQL Critical Quality` คือ shard ฝั่ง non-security ที่คู่กัน มันรันเฉพาะ query คุณภาพ JavaScript/TypeScript แบบ non-security ระดับ error-severity บนพื้นผิวมูลค่าสูงแบบแคบบน Blacksmith Linux runner ขนาดเล็กกว่า guard ของ pull request ตั้งใจให้เล็กกว่าโปรไฟล์ตามกำหนด: PR ที่ไม่ใช่ draft จะรันเฉพาะ shard `agent-runtime-boundary`, `config-boundary`, `core-auth-secrets`, `channel-runtime-boundary`, `gateway-runtime-boundary`, `memory-runtime-boundary`, `mcp-process-runtime-boundary`, `provider-runtime-boundary`, `session-diagnostics-boundary`, `plugin-boundary`, `plugin-sdk-package-contract` และ `plugin-sdk-reply-runtime` ที่ตรงกัน สำหรับการเปลี่ยนแปลงโค้ดการรันคำสั่ง/model/tool ของ agent และการ dispatch การตอบกลับ, โค้ด schema/migration/IO ของ config, โค้ด auth/secrets/sandbox/security, runtime ของช่องทางหลักและช่องทาง Plugin ที่ bundled, protocol/server-method ของ Gateway, runtime ของ memory/ส่วนเชื่อม SDK, MCP/process/การส่งออกขาออก, runtime ของ provider/catalog model, diagnostics ของ session/คิวการส่ง, loader ของ Plugin, Plugin SDK/สัญญา package หรือ runtime การตอบกลับของ Plugin SDK การเปลี่ยนแปลง config ของ CodeQL และเวิร์กโฟลว์คุณภาพจะรัน shard คุณภาพ PR ทั้งสิบสองรายการ +`CodeQL Critical Quality` คือ shard ที่จับคู่กันซึ่งไม่ใช่ความปลอดภัย รันเฉพาะคิวรีคุณภาพ JavaScript/TypeScript ที่ไม่ใช่ความปลอดภัยและมี error-severity บนพื้นผิวมูลค่าสูงที่มีขอบเขตแคบ บน Blacksmith Linux runner ขนาดเล็กกว่า pull request guard ของมันตั้งใจให้เล็กกว่า profile ตามกำหนดเวลา: PR ที่ไม่ใช่ draft จะรันเฉพาะ shard ที่จับคู่กัน ได้แก่ `agent-runtime-boundary`, `config-boundary`, `core-auth-secrets`, `channel-runtime-boundary`, `gateway-runtime-boundary`, `memory-runtime-boundary`, `mcp-process-runtime-boundary`, `provider-runtime-boundary`, `session-diagnostics-boundary`, `plugin-boundary`, `plugin-sdk-package-contract` และ `plugin-sdk-reply-runtime` สำหรับการเปลี่ยนแปลงโค้ดการรันคำสั่ง/model/tool ของ agent และการ dispatch reply, โค้ด config schema/migration/IO, โค้ด auth/secrets/sandbox/security, core channel และ bundled channel Plugin runtime, Gateway protocol/server-method, memory runtime/SDK glue, MCP/process/outbound delivery, provider runtime/model catalog, session diagnostics/delivery queues, Plugin loader, Plugin SDK/package-contract หรือ Plugin SDK reply runtime การเปลี่ยนแปลง CodeQL config และ quality workflow จะรัน PR quality shard ทั้งสิบสองรายการ manual dispatch รับค่า: @@ -424,40 +424,40 @@ manual dispatch รับค่า: profile=all|agent-runtime-boundary|config-boundary|core-auth-secrets|channel-runtime-boundary|gateway-runtime-boundary|memory-runtime-boundary|mcp-process-runtime-boundary|plugin-boundary|plugin-sdk-package-contract|plugin-sdk-reply-runtime|provider-runtime-boundary|session-diagnostics-boundary ``` -โปรไฟล์แบบแคบเป็น hook สำหรับการสอน/การวนปรับ เพื่อรัน shard คุณภาพหนึ่งรายการแบบแยกเดี่ยว +profile แบบแคบเป็น hook สำหรับสอน/วนปรับปรุงเพื่อรัน quality shard หนึ่งรายการแยกเดี่ยว -| หมวดหมู่ | พื้นผิว | +| หมวดหมู่ | พื้นผิว | | ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `/codeql-critical-quality/core-auth-secrets` | โค้ดขอบเขตความปลอดภัยของการยืนยันตัวตน, secret, แซนด์บ็อกซ์, Cron และ Gateway | -| `/codeql-critical-quality/config-boundary` | สัญญาของ schema, migration, normalization และ IO ของ config | -| `/codeql-critical-quality/gateway-runtime-boundary` | schema ของ protocol Gateway และสัญญา method ของเซิร์ฟเวอร์ | -| `/codeql-critical-quality/channel-runtime-boundary` | สัญญา implementation ของช่องทางหลักและช่องทาง Plugin ที่ bundled | -| `/codeql-critical-quality/agent-runtime-boundary` | สัญญา runtime ของการรันคำสั่ง, การ dispatch model/provider, การ dispatch และคิว auto-reply และ control plane ของ ACP | -| `/codeql-critical-quality/mcp-process-runtime-boundary` | เซิร์ฟเวอร์ MCP และ bridge ของเครื่องมือ, helper การกำกับดูแล process และสัญญาการส่งออกขาออก | -| `/codeql-critical-quality/memory-runtime-boundary` | memory host SDK, facade ของ memory runtime, alias ของ memory Plugin SDK, ส่วนเชื่อมการเปิดใช้งาน memory runtime และคำสั่ง doctor ของ memory | -| `/codeql-critical-quality/session-diagnostics-boundary` | ภายในคิวตอบกลับ, คิวการส่ง session, helper การผูก/ส่ง session ขาออก, พื้นผิวชุด event/log เพื่อ diagnostics และสัญญา CLI ของ session doctor | -| `/codeql-critical-quality/plugin-sdk-reply-runtime` | การ dispatch การตอบกลับขาเข้าของ Plugin SDK, payload การตอบกลับ/helper การแบ่ง chunk/runtime, ตัวเลือกการตอบกลับของช่องทาง, คิวการส่ง และ helper การผูก session/thread | -| `/codeql-critical-quality/provider-runtime-boundary` | การ normalize catalog model, การยืนยันตัวตนและ discovery ของ provider, การลงทะเบียน runtime ของ provider, ค่าเริ่มต้น/catalog ของ provider และ registry สำหรับ web/search/fetch/embedding | -| `/codeql-critical-quality/ui-control-plane` | การ bootstrap Control UI, persistence แบบ local, control flow ของ Gateway และสัญญา runtime ของ control plane งาน | -| `/codeql-critical-quality/web-media-runtime-boundary` | สัญญา runtime ของ core web fetch/search, media IO, ความเข้าใจสื่อ, image-generation และ media-generation | -| `/codeql-critical-quality/plugin-boundary` | สัญญาของ loader, registry, public-surface และ entrypoint ของ Plugin SDK | -| `/codeql-critical-quality/plugin-sdk-package-contract` | source ของ Plugin SDK ฝั่ง package ที่เผยแพร่ และ helper สัญญา package ของ plugin | +| `/codeql-critical-quality/core-auth-secrets` | โค้ดขอบเขตความปลอดภัยของ Auth, ความลับ, sandbox, cron และ Gateway | +| `/codeql-critical-quality/config-boundary` | สัญญา config schema, migration, normalization และ IO | +| `/codeql-critical-quality/gateway-runtime-boundary` | schema ของ Gateway protocol และสัญญา server method | +| `/codeql-critical-quality/channel-runtime-boundary` | สัญญาการทำงานของ core channel และ bundled channel Plugin | +| `/codeql-critical-quality/agent-runtime-boundary` | การรันคำสั่ง, การ dispatch model/provider, การ dispatch และ queue ของ auto-reply และสัญญา runtime ของ ACP control-plane | +| `/codeql-critical-quality/mcp-process-runtime-boundary` | เซิร์ฟเวอร์ MCP และสะพานเชื่อม tool, helper สำหรับกำกับดูแล process และสัญญาการส่งออกขาออก | +| `/codeql-critical-quality/memory-runtime-boundary` | memory host SDK, memory runtime facade, alias ของ memory Plugin SDK, glue สำหรับเปิดใช้งาน memory runtime และคำสั่ง memory doctor | +| `/codeql-critical-quality/session-diagnostics-boundary` | ส่วนภายในของ reply queue, queue การส่ง session, helper การ bind/ส่ง outbound session, พื้นผิว diagnostic event/log bundle และสัญญา CLI ของ session doctor | +| `/codeql-critical-quality/plugin-sdk-reply-runtime` | การ dispatch inbound reply ของ Plugin SDK, helper สำหรับ reply payload/chunking/runtime, ตัวเลือก channel reply, delivery queue และ helper การ bind session/thread | +| `/codeql-critical-quality/provider-runtime-boundary` | การ normalize model catalog, provider auth และ discovery, การลงทะเบียน provider runtime, provider defaults/catalogs และ registry ของ web/search/fetch/embedding | +| `/codeql-critical-quality/ui-control-plane` | การ bootstrap ของ Control UI, persistence ภายในเครื่อง, flow การควบคุม Gateway และสัญญา runtime ของ task control-plane | +| `/codeql-critical-quality/web-media-runtime-boundary` | core web fetch/search, media IO, media understanding, image-generation และสัญญา runtime ของ media-generation | +| `/codeql-critical-quality/plugin-boundary` | สัญญา loader, registry, public-surface และ entrypoint ของ Plugin SDK | +| `/codeql-critical-quality/plugin-sdk-package-contract` | source ของ Plugin SDK ฝั่ง package ที่เผยแพร่แล้ว และ helper สัญญา package ของ Plugin | -คุณภาพแยกออกจากความปลอดภัย เพื่อให้ finding ด้านคุณภาพสามารถจัดกำหนดเวลา วัดผล ปิดใช้งาน หรือขยายได้โดยไม่บดบังสัญญาณด้านความปลอดภัย ควรเพิ่มการขยาย CodeQL สำหรับ Swift, Python และ bundled-plugin กลับมาเป็นงานติดตามผลแบบจำกัดขอบเขตหรือแบ่ง shard เท่านั้นหลังจากโปรไฟล์แบบแคบมี runtime และสัญญาณที่เสถียรแล้ว +คุณภาพแยกจากความปลอดภัยเพื่อให้ findings ด้านคุณภาพสามารถถูกกำหนดเวลา วัดผล ปิดใช้งาน หรือขยายได้โดยไม่บดบังสัญญาณความปลอดภัย ควรเพิ่มการขยาย CodeQL สำหรับ Swift, Python และ bundled-plugin กลับเข้ามาเป็นงานติดตามที่มีขอบเขตหรือแบ่ง shard แล้วเท่านั้น หลังจาก profile แบบแคบมี runtime และสัญญาณที่เสถียร -## เวิร์กโฟลว์การบำรุงรักษา +## เวิร์กโฟลว์บำรุงรักษา ### Docs Agent -เวิร์กโฟลว์ `Docs Agent` เป็น lane การบำรุงรักษา Codex แบบขับเคลื่อนด้วย event สำหรับทำให้เอกสารที่มีอยู่สอดคล้องกับการเปลี่ยนแปลงที่เพิ่ง land มันไม่มี schedule ล้วน: การรัน CI ของ push ที่สำเร็จจาก non-bot บน `main` สามารถ trigger มันได้ และ manual dispatch สามารถรันได้โดยตรง การเรียกผ่าน workflow-run จะข้ามเมื่อ `main` เดินหน้าไปแล้ว หรือเมื่อมีการสร้างการรัน Docs Agent ที่ไม่ถูกข้ามรายการอื่นในชั่วโมงที่ผ่านมา เมื่อรัน มันจะตรวจทานช่วง commit ตั้งแต่ source SHA ของ Docs Agent ที่ไม่ถูกข้ามรายการก่อนหน้าไปจนถึง `main` ปัจจุบัน ดังนั้นการรันรายชั่วโมงหนึ่งครั้งสามารถครอบคลุมการเปลี่ยนแปลงทั้งหมดบน main ที่สะสมตั้งแต่การตรวจเอกสารครั้งล่าสุด +เวิร์กโฟลว์ `Docs Agent` เป็นเลนบำรุงรักษา Codex แบบขับเคลื่อนด้วยเหตุการณ์สำหรับรักษาเอกสารที่มีอยู่ให้สอดคล้องกับการเปลี่ยนแปลงที่เพิ่ง land ไม่มี schedule ล้วน: การรัน CI จาก push ที่สำเร็จและไม่ใช่ bot บน `main` สามารถ trigger ได้ และ manual dispatch สามารถรันได้โดยตรง การเรียกจาก workflow-run จะข้ามเมื่อ `main` ขยับต่อไปแล้ว หรือเมื่อมีการสร้างการรัน Docs Agent ที่ไม่ถูกข้ามรายการอื่นในชั่วโมงที่ผ่านมา เมื่อรัน จะตรวจสอบช่วง commit ตั้งแต่ source SHA ของ Docs Agent ที่ไม่ถูกข้ามรายการก่อนหน้าไปจนถึง `main` ปัจจุบัน ดังนั้นการรันรายชั่วโมงหนึ่งครั้งจึงครอบคลุมการเปลี่ยนแปลงทั้งหมดบน main ที่สะสมตั้งแต่รอบเอกสารครั้งล่าสุดได้ ### Test Performance Agent -เวิร์กโฟลว์ `Test Performance Agent` เป็น lane การบำรุงรักษา Codex แบบขับเคลื่อนด้วย event สำหรับ test ที่ช้า มันไม่มี schedule ล้วน: การรัน CI ของ push ที่สำเร็จจาก non-bot บน `main` สามารถ trigger มันได้ แต่จะข้ามหาก invocation ผ่าน workflow-run อื่นรันไปแล้วหรือกำลังรันอยู่ในวัน UTC นั้น manual dispatch จะข้าม gate กิจกรรมรายวันนั้น lane จะสร้างรายงานประสิทธิภาพ Vitest แบบ full-suite ที่จัดกลุ่ม ให้ Codex ทำเฉพาะการแก้ประสิทธิภาพ test ขนาดเล็กที่รักษา coverage แทน refactor กว้าง จากนั้นรันรายงาน full-suite อีกครั้งและปฏิเสธการเปลี่ยนแปลงที่ลดจำนวน baseline test ที่ผ่าน หาก baseline มี test ล้มเหลว Codex อาจแก้เฉพาะ failure ที่ชัดเจน และรายงาน full-suite หลัง agent ต้องผ่านก่อนที่จะ commit สิ่งใด เมื่อ `main` เดินหน้าก่อน bot push จะ land lane จะ rebase patch ที่ตรวจสอบแล้ว รัน `pnpm check:changed` อีกครั้ง และลอง push ซ้ำ patch เก่าที่ขัดแย้งจะถูกข้าม มันใช้ GitHub-hosted Ubuntu เพื่อให้ Codex action รักษาท่าทีความปลอดภัยแบบ drop-sudo เดียวกับ docs agent ได้ +เวิร์กโฟลว์ `Test Performance Agent` เป็นเลนบำรุงรักษา Codex แบบขับเคลื่อนด้วยเหตุการณ์สำหรับ test ที่ช้า ไม่มี schedule ล้วน: การรัน CI จาก push ที่สำเร็จและไม่ใช่ bot บน `main` สามารถ trigger ได้ แต่จะข้ามหากการเรียกจาก workflow-run รายการอื่นได้รันแล้วหรือกำลังรันอยู่ในวัน UTC นั้น Manual dispatch จะข้าม gate กิจกรรมรายวันนั้น เลนนี้สร้างรายงานประสิทธิภาพ Vitest แบบ grouped สำหรับทั้งชุด อนุญาตให้ Codex ทำเฉพาะการแก้ประสิทธิภาพ test ขนาดเล็กที่ยังคง coverage ไว้ แทนที่จะทำ refactor กว้าง จากนั้นรันรายงานทั้งชุดอีกครั้งและปฏิเสธการเปลี่ยนแปลงที่ลดจำนวน test baseline ที่ผ่าน หาก baseline มี test ที่ล้มเหลว Codex อาจแก้เฉพาะความล้มเหลวที่ชัดเจน และรายงานทั้งชุดหลัง agent ต้องผ่านก่อนที่จะ commit อะไรก็ตาม เมื่อ `main` เดินหน้าก่อน bot push จะ land เลนนี้จะ rebase patch ที่ตรวจสอบแล้ว รัน `pnpm check:changed` อีกครั้ง และลอง push ใหม่; patch เก่าที่ขัดแย้งกันจะถูกข้าม ใช้ GitHub-hosted Ubuntu เพื่อให้ Codex action คง posture ความปลอดภัยแบบ drop-sudo เดียวกับ docs agent ได้ ### Duplicate PRs After Merge -เวิร์กโฟลว์ `Duplicate PRs After Merge` เป็นเวิร์กโฟลว์ maintainer แบบ manual สำหรับการล้าง duplicate หลัง land ค่าเริ่มต้นเป็น dry-run และจะปิดเฉพาะ PR ที่ระบุอย่างชัดเจนเมื่อ `apply=true` ก่อนแก้ไข GitHub มันตรวจสอบว่า PR ที่ land แล้วถูก merge แล้ว และ duplicate แต่ละรายการมี either issue ที่อ้างอิงร่วมกันหรือ hunk ที่เปลี่ยนแปลงทับซ้อนกัน +เวิร์กโฟลว์ `Duplicate PRs After Merge` เป็นเวิร์กโฟลว์แมนนวลสำหรับ maintainer เพื่อทำความสะอาดรายการซ้ำหลัง land ค่าเริ่มต้นเป็น dry-run และจะปิดเฉพาะ PR ที่ระบุไว้อย่างชัดเจนเมื่อ `apply=true` ก่อนเปลี่ยนแปลง GitHub จะตรวจสอบว่า PR ที่ land ถูก merge แล้ว และแต่ละรายการซ้ำมี issue ที่อ้างอิงร่วมกันหรือมี hunk ที่เปลี่ยนแปลงทับซ้อนกัน ```bash gh workflow run duplicate-after-merge.yml \ @@ -466,38 +466,115 @@ gh workflow run duplicate-after-merge.yml \ -f apply=true ``` -## gate การตรวจ local และการ route การเปลี่ยนแปลง +## gate การตรวจสอบภายในเครื่องและการ route การเปลี่ยนแปลง -ตรรกะ changed-lane แบบ local อยู่ใน `scripts/changed-lanes.mjs` และถูก execute โดย `scripts/check-changed.mjs` gate การตรวจ local นั้นเข้มงวดกับขอบเขตสถาปัตยกรรมมากกว่า scope ของแพลตฟอร์ม CI แบบกว้าง: +ตรรกะ changed-lane ภายในเครื่องอยู่ใน `scripts/changed-lanes.mjs` และถูกเรียกใช้โดย `scripts/check-changed.mjs` gate การตรวจสอบภายในเครื่องนั้นเข้มงวดเรื่องขอบเขตสถาปัตยกรรมมากกว่าขอบเขตแพลตฟอร์ม CI แบบกว้าง: -- การเปลี่ยนแปลง production ของ core จะรัน typecheck ของ core prod และ core test รวมถึง lint/guard ของ core; -- การเปลี่ยนแปลงเฉพาะ test ของ core จะรันเฉพาะ typecheck ของ core test รวมถึง lint ของ core; -- การเปลี่ยนแปลง production ของ extension จะรัน typecheck ของ extension prod และ extension test รวมถึง lint ของ extension; -- การเปลี่ยนแปลงเฉพาะ test ของ extension จะรัน typecheck ของ extension test รวมถึง lint ของ extension; -- การเปลี่ยนแปลง public Plugin SDK หรือสัญญา plugin จะขยายไปยัง typecheck ของ extension เพราะ extension พึ่งพาสัญญา core เหล่านั้น (การกวาด Vitest ของ extension ยังคงเป็นงาน test ที่ explicit); -- การ bump เวอร์ชันแบบ release metadata-only จะรันการตรวจ version/config/root-dependency แบบเจาะจง; -- การเปลี่ยนแปลง root/config ที่ไม่รู้จักจะ fail safe ไปยัง check lane ทั้งหมด +- การเปลี่ยนแปลง core production รัน typecheck ของ core prod และ core test พร้อม core lint/guards; +- การเปลี่ยนแปลงเฉพาะ core test รันเฉพาะ typecheck ของ core test พร้อม core lint; +- การเปลี่ยนแปลง extension production รัน typecheck ของ extension prod และ extension test พร้อม extension lint; +- การเปลี่ยนแปลงเฉพาะ extension test รัน typecheck ของ extension test พร้อม extension lint; +- การเปลี่ยนแปลง public Plugin SDK หรือ plugin-contract ขยายไปยัง extension typecheck เพราะ extension พึ่งพาสัญญา core เหล่านั้น (การกวาด Vitest extension ยังคงเป็นงาน test ที่ต้องระบุชัดเจน); +- การ bump version ที่เป็น release metadata เท่านั้น รันการตรวจสอบ version/config/root-dependency แบบ targeted; +- การเปลี่ยนแปลง root/config ที่ไม่ทราบประเภทจะ fail safe ไปยังทุก check lane -routing ของ changed-test แบบ local อยู่ใน `scripts/test-projects.test-support.mjs` และตั้งใจให้ถูกกว่า `check:changed`: การแก้ test โดยตรงจะรันตัวเอง การแก้ source จะเลือก mapping ที่ explicit ก่อน จากนั้นจึงใช้ test ข้างเคียงและ dependent จาก import-graph config การส่ง group-room ร่วมเป็นหนึ่งใน mapping ที่ explicit: การเปลี่ยนแปลง config visible-reply ของ group, โหมดการส่ง reply ของ source หรือ prompt ระบบของ message-tool จะ route ผ่าน core reply tests รวมถึง regression การส่งของ Discord และ Slack เพื่อให้การเปลี่ยน default ร่วม fail ก่อน PR push ครั้งแรก ใช้ `OPENCLAW_TEST_CHANGED_BROAD=1 pnpm test:changed` เฉพาะเมื่อการเปลี่ยนแปลงกว้างระดับ harness จนชุด mapped ราคาถูกไม่ใช่ proxy ที่น่าเชื่อถือ +การ route changed-test ภายในเครื่องอยู่ใน `scripts/test-projects.test-support.mjs` และตั้งใจให้ถูกกว่า `check:changed`: การแก้ test โดยตรงรันตัวเอง, การแก้ source จะใช้ mapping ชัดเจนก่อน แล้วจึง sibling tests และ dependents จาก import-graph config การส่ง group-room ที่แชร์เป็นหนึ่งใน mapping ที่ชัดเจน: การเปลี่ยนแปลงต่อ config visible-reply ของ group, source reply delivery mode หรือ system prompt ของ message-tool จะ route ผ่าน core reply tests พร้อม regression การส่ง Discord และ Slack เพื่อให้การเปลี่ยนค่าเริ่มต้นที่แชร์ล้มเหลวก่อน PR push แรก ใช้ `OPENCLAW_TEST_CHANGED_BROAD=1 pnpm test:changed` เฉพาะเมื่อการเปลี่ยนแปลงกว้างระดับ harness จนชุด mapped ราคาถูกไม่ใช่ proxy ที่น่าเชื่อถือ -## การตรวจสอบด้วย Testbox +## การตรวจสอบ Testbox -เรียกใช้ Testbox จากรากของที่เก็บโค้ด และควรใช้กล่องที่วอร์มใหม่สำหรับการตรวจสอบวงกว้าง ก่อนใช้เกตที่ช้าบนกล่องที่ถูกนำกลับมาใช้ใหม่ หมดอายุ หรือเพิ่งรายงานการซิงก์ที่ใหญ่ผิดคาด ให้เรียกใช้ `pnpm testbox:sanity` ภายในกล่องก่อน +เรียกใช้ Testbox จากรากของรีโพ และควรใช้กล่องใหม่ที่วอร์มไว้แล้วสำหรับหลักฐานวงกว้าง ก่อนใช้ gate ที่ช้ากับกล่องที่ถูกนำกลับมาใช้ซ้ำ หมดอายุ หรือเพิ่งรายงานการซิงก์ที่ใหญ่ผิดคาด ให้เรียกใช้ `pnpm testbox:sanity` ภายในกล่องก่อน -การตรวจสอบ sanity จะล้มเหลวอย่างรวดเร็วเมื่อไฟล์รากที่จำเป็น เช่น `pnpm-lock.yaml` หายไป หรือเมื่อ `git status --short` แสดงการลบไฟล์ที่ติดตามแล้วอย่างน้อย 200 รายการ โดยปกติหมายความว่าสถานะการซิงก์ระยะไกลไม่ใช่สำเนา PR ที่เชื่อถือได้ ให้หยุดกล่องนั้นและวอร์มกล่องใหม่แทนการดีบักความล้มเหลวของการทดสอบผลิตภัณฑ์ สำหรับ PR ที่ตั้งใจลบไฟล์จำนวนมาก ให้ตั้งค่า `OPENCLAW_TESTBOX_ALLOW_MASS_DELETIONS=1` สำหรับการรัน sanity นั้น +การตรวจสอบ sanity จะล้มเหลวอย่างรวดเร็วเมื่อไฟล์รากที่จำเป็น เช่น `pnpm-lock.yaml` หายไป หรือเมื่อ `git status --short` แสดงการลบไฟล์ที่ติดตามไว้อย่างน้อย 200 รายการ โดยปกติหมายความว่าสถานะการซิงก์ระยะไกลไม่ใช่สำเนาของ PR ที่เชื่อถือได้ ให้หยุดกล่องนั้นและวอร์มกล่องใหม่แทนการดีบักความล้มเหลวของการทดสอบผลิตภัณฑ์ สำหรับ PR ที่ตั้งใจลบไฟล์จำนวนมาก ให้ตั้งค่า `OPENCLAW_TESTBOX_ALLOW_MASS_DELETIONS=1` สำหรับการเรียก sanity ครั้งนั้น -`pnpm testbox:run` ยังยุติการเรียกใช้ Blacksmith CLI ในเครื่องที่ค้างอยู่ในเฟสซิงก์นานกว่าห้านาทีโดยไม่มีเอาต์พุตหลังซิงก์ ตั้งค่า `OPENCLAW_TESTBOX_SYNC_TIMEOUT_MS=0` เพื่อปิดใช้งานตัวป้องกันนั้น หรือใช้ค่ามิลลิวินาทีที่มากขึ้นสำหรับ diff ในเครื่องที่ใหญ่ผิดปกติ +`pnpm testbox:run` ยังยุติการเรียกใช้ Blacksmith CLI ในเครื่องที่ค้างอยู่ในช่วงซิงก์นานกว่าห้านาทีโดยไม่มีเอาต์พุตหลังซิงก์ ตั้งค่า `OPENCLAW_TESTBOX_SYNC_TIMEOUT_MS=0` เพื่อปิด guard นั้น หรือใช้ค่ามิลลิวินาทีที่มากขึ้นสำหรับ diff ในเครื่องที่ใหญ่ผิดปกติ -Crabbox คือเส้นทางกล่องระยะไกลลำดับที่สองที่ repo เป็นเจ้าของสำหรับการตรวจสอบบน Linux เมื่อ Blacksmith ไม่พร้อมใช้งาน หรือเมื่อควรใช้ความจุคลาวด์ที่เป็นเจ้าของเองมากกว่า ให้วอร์มกล่อง ไฮเดรตผ่านเวิร์กโฟลว์ของโปรเจ็กต์ แล้วเรียกใช้คำสั่งผ่าน Crabbox CLI: +Crabbox คือ wrapper กล่องระยะไกลที่รีโพเป็นเจ้าของสำหรับหลักฐาน Linux ของผู้ดูแล ใช้เมื่อ check กว้างเกินไปสำหรับ local edit loop, เมื่อความสอดคล้องกับ CI สำคัญ, หรือเมื่อหลักฐานต้องใช้ secrets, Docker, package lanes, กล่องที่นำกลับมาใช้ซ้ำได้, หรือบันทึกระยะไกล แบ็กเอนด์ OpenClaw ปกติคือ `blacksmith-testbox`; ความจุ AWS/Hetzner ที่เป็นเจ้าของเป็นทางสำรองเมื่อ Blacksmith ขัดข้อง มีปัญหาโควตา หรือมีการทดสอบความจุที่เป็นเจ้าของอย่างชัดเจน + +ก่อนเรียกใช้ครั้งแรก ให้ตรวจ wrapper จากรากของรีโพ: ```bash -pnpm crabbox:warmup -- --idle-timeout 90m -pnpm crabbox:hydrate -- --id -pnpm crabbox:run -- --id --shell "OPENCLAW_TESTBOX=1 pnpm check:changed" -pnpm crabbox:stop -- +pnpm crabbox:run -- --help | sed -n '1,120p' ``` -`.crabbox.yaml` เป็นเจ้าของค่าเริ่มต้นของ provider, sync และการไฮเดรต GitHub Actions โดยจะไม่รวม `.git` ในเครื่อง เพื่อให้ checkout ของ Actions ที่ถูกไฮเดรตเก็บเมทาดาทา Git ระยะไกลของตัวเองไว้ แทนการซิงก์ remote และ object store ในเครื่องของ maintainer และจะไม่รวม artifact ของ runtime/build ในเครื่องที่ไม่ควรถูกถ่ายโอนเลย `.github/workflows/crabbox-hydrate.yml` เป็นเจ้าของ checkout, การตั้งค่า Node/pnpm, การ fetch `origin/main` และการส่งต่อสภาพแวดล้อมที่ไม่ใช่ความลับซึ่งคำสั่ง `crabbox run --id ` ภายหลังจะ source +wrapper ของรีโพจะปฏิเสธไบนารี Crabbox ที่เก่าและไม่ได้ประกาศ `blacksmith-testbox` ให้ส่ง provider อย่างชัดเจนแม้ว่า `.crabbox.yaml` จะมีค่าเริ่มต้น owned-cloud อยู่แล้ว + +Changed gate: + +```bash +pnpm crabbox:run -- --provider blacksmith-testbox \ + --blacksmith-org openclaw \ + --blacksmith-workflow .github/workflows/ci-check-testbox.yml \ + --blacksmith-job check \ + --blacksmith-ref main \ + --idle-timeout 90m \ + --ttl 240m \ + --timing-json \ + --shell -- \ + "env CI=1 NODE_OPTIONS=--max-old-space-size=4096 OPENCLAW_TEST_PROJECTS_PARALLEL=6 OPENCLAW_VITEST_MAX_WORKERS=1 OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS=900000 pnpm check:changed" +``` + +เรียกใช้การทดสอบเฉพาะจุดซ้ำ: + +```bash +pnpm crabbox:run -- --provider blacksmith-testbox \ + --blacksmith-org openclaw \ + --blacksmith-workflow .github/workflows/ci-check-testbox.yml \ + --blacksmith-job check \ + --blacksmith-ref main \ + --idle-timeout 90m \ + --ttl 240m \ + --timing-json \ + --shell -- \ + "env CI=1 NODE_OPTIONS=--max-old-space-size=4096 OPENCLAW_VITEST_MAX_WORKERS=1 OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS=900000 pnpm test " +``` + +ชุดทดสอบเต็ม: + +```bash +pnpm crabbox:run -- --provider blacksmith-testbox \ + --blacksmith-org openclaw \ + --blacksmith-workflow .github/workflows/ci-check-testbox.yml \ + --blacksmith-job check \ + --blacksmith-ref main \ + --idle-timeout 90m \ + --ttl 240m \ + --timing-json \ + --shell -- \ + "env CI=1 NODE_OPTIONS=--max-old-space-size=4096 OPENCLAW_TEST_PROJECTS_PARALLEL=6 OPENCLAW_VITEST_MAX_WORKERS=1 OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS=900000 pnpm test" +``` + +อ่านสรุป JSON สุดท้าย ฟิลด์ที่มีประโยชน์คือ `provider`, `leaseId`, `syncDelegated`, `exitCode`, `commandMs`, และ `totalMs` การเรียกใช้ Crabbox แบบครั้งเดียวที่หนุนด้วย Blacksmith ควรหยุด Testbox โดยอัตโนมัติ หากการเรียกใช้ถูกขัดจังหวะหรือการล้างข้อมูลไม่ชัดเจน ให้ตรวจกล่องที่ยังทำงานอยู่และหยุดเฉพาะกล่องที่คุณสร้าง: + +```bash +blacksmith testbox list +blacksmith testbox stop --id +``` + +ใช้การนำกลับมาใช้ซ้ำเฉพาะเมื่อคุณตั้งใจต้องใช้หลายคำสั่งบนกล่องเดียวกันที่ hydrate แล้ว: + +```bash +pnpm crabbox:run -- --provider blacksmith-testbox --id --no-sync --timing-json --shell -- "pnpm test " +pnpm crabbox:stop -- +``` + +หาก Crabbox เป็นชั้นที่เสียแต่ Blacksmith เองยังทำงาน ให้ใช้ Blacksmith โดยตรงเป็นทางสำรองแบบจำกัดขอบเขต: + +```bash +blacksmith testbox warmup ci-check-testbox.yml --ref main --idle-timeout 90 +blacksmith testbox run --id "env CI=1 NODE_OPTIONS=--max-old-space-size=4096 OPENCLAW_TEST_PROJECTS_PARALLEL=6 OPENCLAW_VITEST_MAX_WORKERS=1 OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS=900000 pnpm check:changed" +blacksmith testbox stop --id +``` + +ยกระดับไปใช้ความจุ Crabbox ที่เป็นเจ้าของเฉพาะเมื่อ Blacksmith ล่ม ถูกจำกัดโควตา ไม่มีสภาพแวดล้อมที่ต้องใช้ หรือความจุที่เป็นเจ้าของคือเป้าหมายอย่างชัดเจน: + +```bash +pnpm crabbox:warmup -- --provider aws --class beast --market on-demand --idle-timeout 90m +pnpm crabbox:hydrate -- --id +pnpm crabbox:run -- --id --timing-json --shell -- "env NODE_OPTIONS=--max-old-space-size=4096 OPENCLAW_TEST_PROJECTS_PARALLEL=6 OPENCLAW_VITEST_MAX_WORKERS=1 OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS=900000 pnpm check:changed" +pnpm crabbox:stop -- +``` + +`.crabbox.yaml` เป็นเจ้าของค่าเริ่มต้นของ provider, sync, และการ hydrate ของ GitHub Actions สำหรับ owned-cloud lanes ไฟล์นี้ยกเว้น `.git` ในเครื่องเพื่อให้ checkout ของ Actions ที่ hydrate แล้วเก็บ metadata Git ระยะไกลของตัวเอง แทนการซิงก์ remotes และ object stores ในเครื่องของผู้ดูแล และยกเว้น artifact runtime/build ในเครื่องที่ไม่ควรถูกถ่ายโอนโดยเด็ดขาด `.github/workflows/crabbox-hydrate.yml` เป็นเจ้าของ checkout, การตั้งค่า Node/pnpm, การ fetch `origin/main`, และการส่งต่อสภาพแวดล้อมที่ไม่ใช่ secret สำหรับคำสั่ง owned-cloud `crabbox run --id ` ## ที่เกี่ยวข้อง diff --git a/docs/th/cli/plugins.md b/docs/th/cli/plugins.md index 9a8b0fb98..50663c54f 100644 --- a/docs/th/cli/plugins.md +++ b/docs/th/cli/plugins.md @@ -3,13 +3,13 @@ read_when: - คุณต้องการติดตั้งหรือจัดการ Plugin ของ Gateway หรือบันเดิลที่เข้ากันได้ - คุณต้องการดีบักความล้มเหลวในการโหลด Plugin sidebarTitle: Plugins -summary: ข้อมูลอ้างอิง CLI สำหรับ `openclaw plugins` (list, install, marketplace, uninstall, enable/disable, doctor) +summary: คู่มืออ้างอิง CLI สำหรับ `openclaw plugins` (list, install, marketplace, uninstall, enable/disable, doctor) title: Plugin x-i18n: - generated_at: "2026-05-03T21:28:41Z" + generated_at: "2026-05-04T07:03:04Z" model: gpt-5.5 provider: openai - source_hash: d854d052b0a012a86f9c775775676a9a8fe8ae86b2c38a18118f1abf0732174c + source_hash: 36ae7edb12986ead7e126f25e0761bf312b2644b35017181b674082105886776 source_path: cli/plugins.md workflow: 16 --- @@ -18,19 +18,19 @@ x-i18n: - คู่มือสำหรับผู้ใช้ปลายทางในการติดตั้ง เปิดใช้งาน และแก้ปัญหา plugins + คู่มือสำหรับผู้ใช้ปลายทางในการติดตั้ง เปิดใช้งาน และแก้ไขปัญหา plugins - ตัวอย่างสั้น ๆ สำหรับติดตั้ง แสดงรายการ อัปเดต ถอนการติดตั้ง และเผยแพร่ + ตัวอย่างรวดเร็วสำหรับการติดตั้ง แสดงรายการ อัปเดต ถอนการติดตั้ง และเผยแพร่ - โมเดลความเข้ากันได้ของ bundle + โมเดลความเข้ากันได้ของ Bundle - ฟิลด์ manifest และสคีมา config + ฟิลด์ Manifest และสคีมา config - การเสริมความปลอดภัยสำหรับการติดตั้ง plugin + การเพิ่มความแข็งแกร่งด้านความปลอดภัยสำหรับการติดตั้ง plugin @@ -62,14 +62,16 @@ openclaw plugins marketplace list openclaw plugins marketplace list --json ``` -สำหรับการตรวจสอบการติดตั้ง การ inspect การถอนการติดตั้ง หรือการ refresh registry ที่ช้า ให้รันคำสั่งพร้อม `OPENCLAW_PLUGIN_LIFECYCLE_TRACE=1` trace จะเขียนเวลาของแต่ละเฟสไปยัง stderr และยังทำให้เอาต์พุต JSON parse ได้ ดู [การดีบัก](/th/help/debugging#plugin-lifecycle-trace) +สำหรับการตรวจสอบการติดตั้ง การตรวจสอบ การถอนการติดตั้ง หรือการรีเฟรช registry ที่ช้า ให้รัน +คำสั่งพร้อม `OPENCLAW_PLUGIN_LIFECYCLE_TRACE=1` trace จะเขียนเวลาของแต่ละเฟส +ไปยัง stderr และยังคงทำให้เอาต์พุต JSON แยกวิเคราะห์ได้ ดู [การดีบัก](/th/help/debugging#plugin-lifecycle-trace) -plugins ที่ bundled มาพร้อมกับ OpenClaw บางรายการเปิดใช้งานตามค่าเริ่มต้น (เช่น bundled model providers, bundled speech providers และ bundled browser plugin); รายการอื่นต้องใช้ `plugins enable` +plugins ที่รวมมาด้วยจะจัดส่งพร้อม OpenClaw บางตัวเปิดใช้งานตามค่าเริ่มต้น (เช่น provider โมเดลที่รวมมาด้วย, provider คำพูดที่รวมมาด้วย และ browser plugin ที่รวมมาด้วย); ตัวอื่นต้องใช้ `plugins enable` -plugins แบบเนทีฟของ OpenClaw ต้องมาพร้อม `openclaw.plugin.json` ที่มี JSON Schema แบบ inline (`configSchema` แม้จะว่างก็ตาม) bundles ที่เข้ากันได้จะใช้ bundle manifests ของตนเองแทน +plugins แบบเนทีฟของ OpenClaw ต้องจัดส่ง `openclaw.plugin.json` พร้อม JSON Schema แบบอินไลน์ (`configSchema` แม้จะว่างก็ตาม) bundles ที่เข้ากันได้ใช้ manifest ของ bundle ของตัวเองแทน -`plugins list` แสดง `Format: openclaw` หรือ `Format: bundle` เอาต์พุต list/info แบบ verbose ยังแสดง subtype ของ bundle (`codex`, `claude` หรือ `cursor`) พร้อม capabilities ของ bundle ที่ตรวจพบ +`plugins list` แสดง `Format: openclaw` หรือ `Format: bundle` เอาต์พุต list/info แบบละเอียดจะแสดง subtype ของ bundle ด้วย (`codex`, `claude` หรือ `cursor`) พร้อมความสามารถของ bundle ที่ตรวจพบ ### ติดตั้ง @@ -91,100 +93,108 @@ openclaw plugins install --marketplace https://github.com// -ชื่อแพ็กเกจแบบ bare จะติดตั้งจาก npm ตามค่าเริ่มต้นระหว่างช่วง launch cutover ใช้ `clawhub:` สำหรับ ClawHub ปฏิบัติกับการติดตั้ง plugin เหมือนการรันโค้ด ควรใช้เวอร์ชันที่ pin ไว้ +ชื่อ package แบบเปล่าจะติดตั้งจาก npm ตามค่าเริ่มต้นระหว่างช่วงเปลี่ยนผ่านการเปิดตัว ใช้ `clawhub:` สำหรับ ClawHub ให้ปฏิบัติกับการติดตั้ง plugin เหมือนการรันโค้ด ควรใช้เวอร์ชันที่ pin ไว้ -`plugins search` query ClawHub เพื่อค้นหาแพ็กเกจ plugin ที่ติดตั้งได้ และพิมพ์ชื่อแพ็กเกจที่พร้อมติดตั้ง โดยค้นหาแพ็กเกจ code-plugin และ bundle-plugin ไม่ใช่ skills ใช้ `openclaw skills search` สำหรับ ClawHub skills +`plugins search` ค้นหา ClawHub สำหรับ package plugin ที่ติดตั้งได้ และพิมพ์ +ชื่อ package ที่พร้อมติดตั้ง โดยค้นหา package แบบ code-plugin และ bundle-plugin +ไม่ใช่ skills ใช้ `openclaw skills search` สำหรับ ClawHub skills -ClawHub เป็นช่องทางหลักสำหรับการแจกจ่ายและค้นพบ plugins ส่วนใหญ่ Npm ยังคงเป็น fallback ที่รองรับและเป็นเส้นทาง direct-install แพ็กเกจ plugin `@openclaw/*` ที่ OpenClaw เป็นเจ้าของกลับมาเผยแพร่บน npm อีกครั้งแล้ว ดูรายการปัจจุบันได้ที่ [npmjs.com/org/openclaw](https://www.npmjs.com/org/openclaw) หรือ [plugin inventory](/th/plugins/plugin-inventory) การติดตั้ง stable ใช้ `latest` การติดตั้งและอัปเดตใน beta-channel จะใช้ npm `beta` dist-tag ก่อนเมื่อ tag นั้นมีอยู่ จากนั้นจึง fallback เป็น `latest` +ClawHub เป็นพื้นผิวหลักสำหรับการจัดจำหน่ายและการค้นพบของ plugins ส่วนใหญ่ Npm +ยังคงเป็น fallback ที่รองรับและเป็นเส้นทางการติดตั้งโดยตรง package plugin ที่ OpenClaw เป็นเจ้าของ +`@openclaw/*` ถูกเผยแพร่บน npm อีกครั้ง ดูรายการปัจจุบัน +ที่ [npmjs.com/org/openclaw](https://www.npmjs.com/org/openclaw) หรือ +[คลัง plugin](/th/plugins/plugin-inventory) การติดตั้งแบบเสถียรใช้ `latest` +การติดตั้งและอัปเดตในช่อง beta จะเลือกใช้ npm `beta` dist-tag เมื่อ tag นั้น +พร้อมใช้งาน แล้วจึง fallback ไปที่ `latest` - - หากส่วน `plugins` ของคุณอิงกับ `$include` แบบไฟล์เดียว `plugins install/update/enable/disable/uninstall` จะเขียนผ่านไปยังไฟล์ included นั้นและปล่อย `openclaw.json` ไว้ไม่แตะต้อง Root includes, include arrays และ includes ที่มี sibling overrides จะ fail closed แทนที่จะ flatten ดู [Config includes](/th/gateway/configuration) สำหรับรูปแบบที่รองรับ + + หากส่วน `plugins` ของคุณรองรับด้วย `$include` แบบไฟล์เดียว `plugins install/update/enable/disable/uninstall` จะเขียนผ่านไปยังไฟล์ที่ include นั้น และปล่อย `openclaw.json` ไว้ไม่เปลี่ยนแปลง Root includes, include arrays และ includes ที่มี sibling overrides จะ fail closed แทนการ flatten ดู [Config includes](/th/gateway/configuration) สำหรับรูปแบบที่รองรับ - หาก config ไม่ถูกต้องระหว่างติดตั้ง โดยปกติ `plugins install` จะ fail closed และบอกให้คุณรัน `openclaw doctor --fix` ก่อน ระหว่าง Gateway startup และ hot reload config ของ plugin ที่ไม่ถูกต้องจะ fail closed เหมือน config ที่ไม่ถูกต้องอื่น ๆ; `openclaw doctor --fix` สามารถ quarantine entry ของ plugin ที่ไม่ถูกต้องได้ ข้อยกเว้น install-time ที่มีเอกสารกำกับไว้เพียงอย่างเดียวคือเส้นทาง recovery แบบแคบสำหรับ bundled-plugin สำหรับ plugins ที่ opt in เข้า `openclaw.install.allowInvalidConfigRecovery` อย่างชัดเจน + หาก config ไม่ถูกต้องระหว่างการติดตั้ง โดยปกติ `plugins install` จะ fail closed และบอกให้คุณรัน `openclaw doctor --fix` ก่อน ระหว่างการเริ่มต้น Gateway และ hot reload config plugin ที่ไม่ถูกต้องจะ fail closed เหมือน config ที่ไม่ถูกต้องอื่น ๆ; `openclaw doctor --fix` สามารถ quarantine รายการ plugin ที่ไม่ถูกต้องได้ ข้อยกเว้นที่มีเอกสารระบุไว้สำหรับ install-time มีเพียงเส้นทางกู้คืน bundled-plugin แบบแคบสำหรับ plugins ที่ opt in อย่างชัดเจนไปยัง `openclaw.install.allowInvalidConfigRecovery` - - `--force` ใช้ target การติดตั้งเดิมซ้ำและเขียนทับ plugin หรือ hook pack ที่ติดตั้งไว้แล้วในที่เดิม ใช้เมื่อตั้งใจ reinstall id เดิมจาก local path, archive, แพ็กเกจ ClawHub หรือ artifact ของ npm ใหม่ สำหรับการอัปเกรด plugin npm ที่ติดตามอยู่แล้วตามปกติ ควรใช้ `openclaw plugins update ` + + `--force` ใช้เป้าหมายการติดตั้งเดิมซ้ำและเขียนทับ plugin หรือ hook pack ที่ติดตั้งแล้วในตำแหน่งเดิม ใช้เมื่อตั้งใจติดตั้ง id เดิมใหม่จาก path ในเครื่อง, archive, package ClawHub หรือ artifact npm ใหม่ สำหรับการอัปเกรดตามปกติของ npm plugin ที่ติดตามอยู่แล้ว ควรใช้ `openclaw plugins update ` - หากคุณรัน `plugins install` สำหรับ plugin id ที่ติดตั้งไว้แล้ว OpenClaw จะหยุดและชี้คุณไปที่ `plugins update ` สำหรับการอัปเกรดตามปกติ หรือไปที่ `plugins install --force` เมื่อคุณต้องการเขียนทับการติดตั้งปัจจุบันจากแหล่งอื่นจริง ๆ + หากคุณรัน `plugins install` สำหรับ id ของ plugin ที่ติดตั้งอยู่แล้ว OpenClaw จะหยุดและชี้ให้คุณใช้ `plugins update ` สำหรับการอัปเกรดปกติ หรือใช้ `plugins install --force` เมื่อคุณต้องการเขียนทับการติดตั้งปัจจุบันจากแหล่งอื่นจริง ๆ - `--pin` ใช้ได้กับการติดตั้ง npm เท่านั้น ไม่รองรับกับการติดตั้ง `git:`; ใช้ git ref แบบชัดเจน เช่น `git:github.com/acme/plugin@v1.2.3` เมื่อคุณต้องการแหล่งที่ pin ไว้ ไม่รองรับกับ `--marketplace` เพราะการติดตั้งจาก marketplace จะ persist metadata แหล่งที่มาของ marketplace แทน npm spec + `--pin` ใช้กับการติดตั้ง npm เท่านั้น ไม่รองรับกับการติดตั้ง `git:`; ใช้ git ref ที่ชัดเจน เช่น `git:github.com/acme/plugin@v1.2.3` เมื่อคุณต้องการแหล่งที่ pin ไว้ ไม่รองรับกับ `--marketplace` เพราะการติดตั้ง marketplace จะเก็บ metadata แหล่งที่มาของ marketplace แทน npm spec - `--dangerously-force-unsafe-install` เป็นตัวเลือก break-glass สำหรับ false positives ใน dangerous-code scanner ในตัว อนุญาตให้การติดตั้งดำเนินต่อได้แม้ scanner ในตัวจะรายงาน findings ระดับ `critical` แต่จะ **ไม่** bypass บล็อกจาก policy ของ hook `before_install` ของ plugin และจะ **ไม่** bypass scan failures + `--dangerously-force-unsafe-install` เป็นตัวเลือก break-glass สำหรับ false positives ในตัวสแกนโค้ดอันตรายที่มีมาให้ ช่วยให้การติดตั้งดำเนินต่อได้แม้ตัวสแกนที่มีมาให้รายงาน findings ระดับ `critical` แต่จะ **ไม่** ข้าม policy blocks ของ hook `before_install` ของ plugin และ **ไม่** ข้าม scan failures - CLI flag นี้ใช้กับ flow การ install/update plugin การติดตั้ง skill dependencies ที่ Gateway รองรับใช้ request override ที่ตรงกันคือ `dangerouslyForceUnsafeInstall` ส่วน `openclaw skills install` ยังคงเป็น flow download/install skill ของ ClawHub ที่แยกต่างหาก + flag CLI นี้ใช้กับ flow การติดตั้ง/อัปเดต plugin การติดตั้ง dependency ของ skill ที่รองรับโดย Gateway ใช้ request override ที่ตรงกันคือ `dangerouslyForceUnsafeInstall` ขณะที่ `openclaw skills install` ยังคงเป็น flow ดาวน์โหลด/ติดตั้ง ClawHub skill แยกต่างหาก - หาก plugin ที่คุณเผยแพร่บน ClawHub ถูกบล็อกโดย registry scan ให้ใช้ขั้นตอนสำหรับผู้เผยแพร่ใน [ClawHub](/th/tools/clawhub) + หาก plugin ที่คุณเผยแพร่บน ClawHub ถูกบล็อกโดยการสแกน registry ให้ใช้ขั้นตอนของผู้เผยแพร่ใน [ClawHub](/th/tools/clawhub) - `plugins install` ยังเป็นพื้นผิวการติดตั้งสำหรับ hook packs ที่ expose `openclaw.hooks` ใน `package.json` ใช้ `openclaw hooks` สำหรับการมองเห็น hook แบบ filtered และการเปิดใช้งานราย hook ไม่ใช่การติดตั้งแพ็กเกจ + `plugins install` ยังเป็นพื้นผิวการติดตั้งสำหรับ hook packs ที่เปิดเผย `openclaw.hooks` ใน `package.json` ด้วย ใช้ `openclaw hooks` สำหรับการมองเห็น hook แบบกรองและการเปิดใช้งานราย hook ไม่ใช่การติดตั้ง package - Npm specs เป็น **registry-only** (ชื่อแพ็กเกจ + **exact version** หรือ **dist-tag** ที่เป็นตัวเลือก) Git/URL/file specs และ semver ranges จะถูกปฏิเสธ การติดตั้ง dependencies จะรันแบบ project-local พร้อม `--ignore-scripts` เพื่อความปลอดภัย แม้ shell ของคุณจะมี global npm install settings ก็ตาม + Npm specs เป็นแบบ **registry-only** (ชื่อ package + **เวอร์ชันแบบ exact** หรือ **dist-tag** ที่เป็นทางเลือก) Git/URL/file specs และช่วง semver จะถูกปฏิเสธ การติดตั้ง dependency รันแบบ project-local พร้อม `--ignore-scripts` เพื่อความปลอดภัย แม้ shell ของคุณจะมีการตั้งค่า global npm install ก็ตาม - ใช้ `npm:` เมื่อคุณต้องการระบุ npm resolution ให้ชัดเจน Bare package specs จะติดตั้งโดยตรงจาก npm ระหว่าง launch cutover เช่นกัน + ใช้ `npm:` เมื่อคุณต้องการทำให้การ resolve ของ npm ชัดเจน Bare package specs จะติดตั้งโดยตรงจาก npm เช่นกันระหว่างช่วงเปลี่ยนผ่านการเปิดตัว - Bare specs และ `@latest` จะอยู่บน stable track หาก npm resolve สิ่งใดสิ่งหนึ่งเป็น prerelease OpenClaw จะหยุดและขอให้คุณ opt in อย่างชัดเจนด้วย prerelease tag เช่น `@beta`/`@rc` หรือ exact prerelease version เช่น `@1.2.3-beta.4` + Bare specs และ `@latest` จะอยู่บน track เสถียร เวอร์ชัน correction แบบประทับวันที่ของ OpenClaw เช่น `2026.5.3-1` เป็น stable releases สำหรับการตรวจสอบนี้ หาก npm resolve สิ่งใดสิ่งหนึ่งไปเป็น prerelease OpenClaw จะหยุดและขอให้คุณ opt in อย่างชัดเจนด้วย tag prerelease เช่น `@beta`/`@rc` หรือเวอร์ชัน prerelease แบบ exact เช่น `@1.2.3-beta.4` - หาก bare install spec ตรงกับ official plugin id (เช่น `diffs`) OpenClaw จะติดตั้ง catalog entry โดยตรง หากต้องการติดตั้งแพ็กเกจ npm ที่มีชื่อเดียวกัน ให้ใช้ explicit scoped spec (เช่น `@scope/diffs`) + หาก bare install spec ตรงกับ id ของ plugin อย่างเป็นทางการ (เช่น `diffs`) OpenClaw จะติดตั้งรายการ catalog โดยตรง หากต้องการติดตั้ง npm package ที่มีชื่อเดียวกัน ให้ใช้ scoped spec ที่ชัดเจน (เช่น `@scope/diffs`) - ใช้ `git:` เพื่อติดตั้งโดยตรงจาก git repository รูปแบบที่รองรับได้แก่ `git:github.com/owner/repo`, `git:owner/repo`, clone URLs แบบ full `https://`, `ssh://`, `git://`, `file://` และ `git@host:owner/repo.git` เพิ่ม `@` หรือ `#` เพื่อ check out branch, tag หรือ commit ก่อนติดตั้ง + ใช้ `git:` เพื่อติดตั้งโดยตรงจาก git repository รูปแบบที่รองรับได้แก่ `git:github.com/owner/repo`, `git:owner/repo`, clone URLs แบบเต็ม `https://`, `ssh://`, `git://`, `file://` และ `git@host:owner/repo.git` เพิ่ม `@` หรือ `#` เพื่อ checkout branch, tag หรือ commit ก่อนติดตั้ง - การติดตั้งผ่าน Git จะ clone ไปยังไดเรกทอรีชั่วคราว check out ref ที่ร้องขอเมื่อมีอยู่ จากนั้นใช้ตัวติดตั้งไดเรกทอรี plugin ตามปกติ นั่นหมายความว่า manifest validation, dangerous-code scanning, งานติดตั้งของ package-manager และ install records จะทำงานเหมือนการติดตั้ง npm การติดตั้ง git ที่บันทึกไว้จะรวม source URL/ref พร้อม resolved commit เพื่อให้ `openclaw plugins update` สามารถ re-resolve แหล่งที่มาภายหลังได้ + การติดตั้ง Git จะ clone ไปยัง directory ชั่วคราว checkout ref ที่ร้องขอเมื่อมี จากนั้นใช้ตัวติดตั้ง directory plugin ปกติ ซึ่งหมายความว่า manifest validation, การสแกนโค้ดอันตราย, งานติดตั้ง package-manager และบันทึกการติดตั้งจะทำงานเหมือนการติดตั้ง npm การติดตั้ง git ที่บันทึกไว้จะรวม URL/ref แหล่งที่มาและ commit ที่ resolve แล้ว เพื่อให้ `openclaw plugins update` สามารถ re-resolve แหล่งที่มาในภายหลังได้ - หลังจากติดตั้งจาก git ให้ใช้ `openclaw plugins inspect --runtime --json` เพื่อตรวจสอบ runtime registrations เช่น gateway methods และ CLI commands หาก plugin ลงทะเบียน CLI root ด้วย `api.registerCli` ให้รันคำสั่งนั้นโดยตรงผ่าน root CLI ของ OpenClaw เช่น `openclaw demo-plugin ping` + หลังติดตั้งจาก git ให้ใช้ `openclaw plugins inspect --runtime --json` เพื่อตรวจสอบ runtime registrations เช่น gateway methods และ CLI commands หาก plugin ลงทะเบียน CLI root ด้วย `api.registerCli` ให้ execute คำสั่งนั้นโดยตรงผ่าน root CLI ของ OpenClaw เช่น `openclaw demo-plugin ping` - Archives ที่รองรับ: `.zip`, `.tgz`, `.tar.gz`, `.tar` Archives ของ plugin แบบเนทีฟของ OpenClaw ต้องมี `openclaw.plugin.json` ที่ถูกต้องที่ root ของ plugin ที่ extract แล้ว; archives ที่มีเพียง `package.json` จะถูกปฏิเสธก่อน OpenClaw เขียน install records + archives ที่รองรับ: `.zip`, `.tgz`, `.tar.gz`, `.tar` archives ของ OpenClaw plugin แบบเนทีฟต้องมี `openclaw.plugin.json` ที่ถูกต้องที่ root ของ plugin หลังแตกไฟล์; archives ที่มีเฉพาะ `package.json` จะถูกปฏิเสธก่อนที่ OpenClaw จะเขียนบันทึกการติดตั้ง - รองรับการติดตั้งจาก Claude marketplace ด้วย + รองรับการติดตั้ง Claude marketplace ด้วย -การติดตั้ง ClawHub ใช้ locator แบบชัดเจน `clawhub:`: +การติดตั้ง ClawHub ใช้ locator `clawhub:` ที่ชัดเจน: ```bash openclaw plugins install clawhub:openclaw-codex-app-server openclaw plugins install clawhub:openclaw-codex-app-server@1.2.3 ``` -Bare npm-safe plugin specs จะติดตั้งจาก npm ตามค่าเริ่มต้นระหว่าง launch cutover: +Bare npm-safe plugin specs จะติดตั้งจาก npm ตามค่าเริ่มต้นระหว่างช่วงเปลี่ยนผ่านการเปิดตัว: ```bash openclaw plugins install openclaw-codex-app-server ``` -ใช้ `npm:` เพื่อระบุ npm-only resolution ให้ชัดเจน: +ใช้ `npm:` เพื่อทำให้การ resolve แบบ npm-only ชัดเจน: ```bash openclaw plugins install npm:openclaw-codex-app-server openclaw plugins install npm:@scope/plugin-name@1.0.1 ``` -OpenClaw ตรวจสอบ plugin API ที่ประกาศไว้ / ความเข้ากันได้ขั้นต่ำของ gateway ก่อนติดตั้ง เมื่อเวอร์ชัน ClawHub ที่เลือกเผยแพร่ ClawPack artifact, OpenClaw จะดาวน์โหลด `.tgz` แบบ npm-pack ที่มีเวอร์ชัน ตรวจสอบ ClawHub digest header และ artifact digest จากนั้นติดตั้งผ่านเส้นทาง archive ปกติ เวอร์ชัน ClawHub ที่เก่ากว่าและไม่มี ClawPack metadata ยังคงติดตั้งผ่านเส้นทาง legacy package archive verification การติดตั้งที่บันทึกไว้จะเก็บ ClawHub source metadata, artifact kind, npm integrity, npm shasum, tarball name และข้อเท็จจริง ClawPack digest สำหรับการอัปเดตภายหลัง -การติดตั้ง ClawHub แบบไม่ระบุเวอร์ชันจะเก็บ recorded spec แบบไม่ระบุเวอร์ชันไว้ เพื่อให้ `openclaw plugins update` สามารถตามรุ่นใหม่ของ ClawHub ได้; selectors แบบระบุเวอร์ชันหรือ tag ชัดเจน เช่น `clawhub:pkg@1.2.3` และ `clawhub:pkg@beta` จะยังคง pin ไว้กับ selector นั้น +OpenClaw ตรวจสอบ plugin API ที่ประกาศไว้ / ความเข้ากันได้ขั้นต่ำของ gateway ก่อนติดตั้ง เมื่อเวอร์ชัน ClawHub ที่เลือกเผยแพร่ ClawPack artifact OpenClaw จะดาวน์โหลด `.tgz` แบบ npm-pack ที่มีเวอร์ชัน ตรวจสอบ ClawHub digest header และ artifact digest จากนั้นติดตั้งผ่าน path archive ปกติ เวอร์ชัน ClawHub เก่าที่ไม่มี metadata ของ ClawPack ยังคงติดตั้งผ่าน path การตรวจสอบ package archive แบบ legacy การติดตั้งที่บันทึกไว้จะเก็บ metadata แหล่งที่มา ClawHub, ชนิด artifact, npm integrity, npm shasum, ชื่อ tarball และข้อเท็จจริง digest ของ ClawPack ไว้สำหรับการอัปเดตในภายหลัง +การติดตั้ง ClawHub แบบไม่มีเวอร์ชันจะเก็บ recorded spec แบบไม่มีเวอร์ชัน เพื่อให้ `openclaw plugins update` สามารถติดตาม releases ใหม่กว่าของ ClawHub ได้; selectors แบบระบุเวอร์ชันหรือ tag อย่างชัดเจน เช่น `clawhub:pkg@1.2.3` และ `clawhub:pkg@beta` จะยังคง pin อยู่กับ selector นั้น -#### ชวเลข Marketplace +#### รูปย่อของ Marketplace -ใช้ชวเลข `plugin@marketplace` เมื่อชื่อ marketplace มีอยู่ใน local registry cache ของ Claude ที่ `~/.claude/plugins/known_marketplaces.json`: +ใช้รูปย่อ `plugin@marketplace` เมื่อชื่อ marketplace มีอยู่ใน local registry cache ของ Claude ที่ `~/.claude/plugins/known_marketplaces.json`: ```bash openclaw plugins marketplace list openclaw plugins install @ ``` -ใช้ `--marketplace` เมื่อคุณต้องการส่งแหล่งที่มาของ marketplace อย่างชัดเจน: +ใช้ `--marketplace` เมื่อคุณต้องการส่ง marketplace source อย่างชัดเจน: ```bash openclaw plugins install --marketplace @@ -195,30 +205,30 @@ openclaw plugins install --marketplace ./my-marketplace - - ชื่อ Marketplace ที่ Claude รู้จักจาก `~/.claude/plugins/known_marketplaces.json` - - รูท Marketplace ในเครื่องหรือพาธ `marketplace.json` - - ชื่อย่อ repo GitHub เช่น `owner/repo` - - URL repo GitHub เช่น `https://github.com/owner/repo` + - ชื่อ marketplace ที่ Claude รู้จักจาก `~/.claude/plugins/known_marketplaces.json` + - ราก marketplace ในเครื่องหรือพาธ `marketplace.json` + - ชวเลข repo ของ GitHub เช่น `owner/repo` + - URL repo ของ GitHub เช่น `https://github.com/owner/repo` - URL git - - สำหรับ Marketplace ระยะไกลที่โหลดจาก GitHub หรือ git รายการ Plugin ต้องอยู่ภายใน repo Marketplace ที่โคลนมา OpenClaw ยอมรับแหล่งที่มาแบบพาธสัมพัทธ์จาก repo นั้น และปฏิเสธแหล่งที่มา Plugin แบบ HTTP(S), พาธสัมบูรณ์, git, GitHub และแหล่งที่มาอื่นที่ไม่ใช่พาธจาก manifest ระยะไกล + + สำหรับ marketplace ระยะไกลที่โหลดจาก GitHub หรือ git รายการ Plugin ต้องอยู่ภายใน repo marketplace ที่โคลนมา OpenClaw ยอมรับแหล่งที่มาแบบพาธสัมพัทธ์จาก repo นั้น และปฏิเสธแหล่งที่มา Plugin แบบ HTTP(S), พาธสัมบูรณ์, git, GitHub และแหล่งที่มา Plugin อื่นที่ไม่ใช่พาธจาก manifest ระยะไกล -สำหรับพาธและไฟล์เก็บถาวรในเครื่อง OpenClaw จะตรวจจับโดยอัตโนมัติ: +สำหรับพาธในเครื่องและไฟล์ archive OpenClaw ตรวจจับอัตโนมัติ: -- Plugin ดั้งเดิมของ OpenClaw (`openclaw.plugin.json`) +- Plugin แบบเนทีฟของ OpenClaw (`openclaw.plugin.json`) - บันเดิลที่เข้ากันได้กับ Codex (`.codex-plugin/plugin.json`) - บันเดิลที่เข้ากันได้กับ Claude (`.claude-plugin/plugin.json` หรือเลย์เอาต์คอมโพเนนต์ Claude เริ่มต้น) - บันเดิลที่เข้ากันได้กับ Cursor (`.cursor-plugin/plugin.json`) -บันเดิลที่เข้ากันได้จะติดตั้งลงในรูท Plugin ปกติ และเข้าร่วมในโฟลว์ list/info/enable/disable เดียวกัน ปัจจุบันรองรับ Skills ของบันเดิล, command-skills ของ Claude, ค่าเริ่มต้น `settings.json` ของ Claude, ค่าเริ่มต้น `.lsp.json` / `lspServers` ที่ประกาศใน manifest ของ Claude, command-skills ของ Cursor และไดเรกทอรี hook ของ Codex ที่เข้ากันได้ ส่วนความสามารถอื่นของบันเดิลที่ตรวจพบจะแสดงใน diagnostics/info แต่ยังไม่ได้เชื่อมต่อเข้ากับการทำงานของ runtime +บันเดิลที่เข้ากันได้จะติดตั้งลงในราก Plugin ปกติ และเข้าร่วมในโฟลว์ list/info/enable/disable เดียวกัน ปัจจุบันรองรับ Skills ของบันเดิล, command-skills ของ Claude, ค่าเริ่มต้น `settings.json` ของ Claude, ค่าเริ่มต้น `.lsp.json` ของ Claude / `lspServers` ที่ประกาศใน manifest, command-skills ของ Cursor และไดเรกทอรี hook ของ Codex ที่เข้ากันได้ ส่วนความสามารถอื่นของบันเดิลที่ตรวจพบจะแสดงใน diagnostics/info แต่ยังไม่ได้เชื่อมเข้ากับการทำงานขณะรันไทม์ -### รายการ +### แสดงรายการ ```bash openclaw plugins list @@ -231,31 +241,31 @@ openclaw plugins search --json ``` - แสดงเฉพาะ Plugin ที่เปิดใช้งานแล้ว + แสดงเฉพาะ Plugin ที่เปิดใช้งานอยู่ - เปลี่ยนจากมุมมองตารางเป็นบรรทัดรายละเอียดต่อ Plugin พร้อมเมทาดาทา source/origin/version/activation + เปลี่ยนจากมุมมองตารางเป็นบรรทัดรายละเอียดต่อ Plugin พร้อม metadata ของ source/origin/version/activation - รายการ inventory ที่เครื่องอ่านได้ พร้อม diagnostics ของ registry และสถานะการติดตั้ง dependency ของแพ็กเกจ + inventory ที่เครื่องอ่านได้ พร้อม diagnostics ของ registry และสถานะการติดตั้ง dependency ของ package -`plugins list` อ่าน registry Plugin ในเครื่องที่คงอยู่ไว้ก่อน โดยมี fallback ที่สร้างจาก manifest เท่านั้นเมื่อ registry ขาดหายหรือไม่ถูกต้อง คำสั่งนี้มีประโยชน์สำหรับตรวจสอบว่า Plugin ติดตั้งแล้ว เปิดใช้งานแล้ว และมองเห็นได้ในการวางแผนเริ่มต้นแบบเย็นหรือไม่ แต่ไม่ใช่การ probe runtime แบบสดของกระบวนการ Gateway ที่กำลังทำงานอยู่ หลังจากเปลี่ยนโค้ด Plugin, enablement, hook policy หรือ `plugins.load.paths` ให้รีสตาร์ท Gateway ที่ให้บริการ channel ก่อนคาดหวังให้โค้ด `register(api)` หรือ hook ใหม่ทำงาน สำหรับการปรับใช้แบบระยะไกล/คอนเทนเนอร์ ให้ตรวจสอบว่าคุณกำลังรีสตาร์ท child `openclaw gateway run` ตัวจริง ไม่ใช่แค่กระบวนการ wrapper +`plugins list` อ่าน registry ของ Plugin ในเครื่องที่ persisted ไว้ก่อน โดยมี fallback ที่ derive จาก manifest เท่านั้นเมื่อ registry หายไปหรือไม่ถูกต้อง คำสั่งนี้มีประโยชน์สำหรับตรวจว่า Plugin ติดตั้งแล้ว เปิดใช้งานอยู่ และมองเห็นได้ในการวางแผน startup แบบ cold หรือไม่ แต่ไม่ใช่ probe รันไทม์สดของโปรเซส Gateway ที่กำลังรันอยู่ หลังเปลี่ยนโค้ด Plugin, enablement, นโยบาย hook หรือ `plugins.load.paths` ให้รีสตาร์ท Gateway ที่ให้บริการ channel ก่อนคาดหวังให้โค้ด `register(api)` หรือ hook ใหม่ทำงาน สำหรับ deployment ระยะไกล/คอนเทนเนอร์ ให้ตรวจสอบว่าคุณกำลังรีสตาร์ท child ของ `openclaw gateway run` ตัวจริง ไม่ใช่แค่โปรเซส wrapper `plugins list --json` รวม `dependencyStatus` ของแต่ละ Plugin จาก `package.json` -`dependencies` และ `optionalDependencies` OpenClaw ตรวจสอบว่าชื่อแพ็กเกจเหล่านั้นมีอยู่ตามพาธ lookup `node_modules` ปกติของ Node สำหรับ Plugin หรือไม่ โดยจะไม่นำเข้าโค้ด runtime ของ Plugin, ไม่เรียกตัวจัดการแพ็กเกจ และไม่ซ่อม dependency ที่ขาดหาย +`dependencies` และ `optionalDependencies` OpenClaw ตรวจสอบว่าชื่อ package เหล่านั้นอยู่ตามพาธค้นหา `node_modules` ปกติของ Node สำหรับ Plugin นั้นหรือไม่ โดยไม่ import โค้ดรันไทม์ของ Plugin, ไม่รัน package manager และไม่ซ่อม dependency ที่หายไป -`plugins search` เป็นการค้นหาแค็ตตาล็อก ClawHub ระยะไกล คำสั่งนี้ไม่ตรวจสอบสถานะในเครื่อง, ไม่แก้ config, ไม่ติดตั้งแพ็กเกจ และไม่โหลดโค้ด runtime ของ Plugin ผลลัพธ์การค้นหาประกอบด้วยชื่อแพ็กเกจ ClawHub, family, channel, version, summary และคำแนะนำการติดตั้ง เช่น `openclaw plugins install clawhub:` +`plugins search` คือการค้นหาแค็ตตาล็อก ClawHub ระยะไกล คำสั่งนี้ไม่ตรวจสอบสถานะในเครื่อง ไม่แก้ config ไม่ติดตั้ง package และไม่โหลดโค้ดรันไทม์ของ Plugin ผลการค้นหารวมชื่อ package ของ ClawHub, family, channel, version, summary และคำใบ้การติดตั้ง เช่น `openclaw plugins install clawhub:` -สำหรับงาน Plugin ที่บันเดิลไว้ภายในอิมเมจ Docker ที่แพ็กเกจแล้ว ให้ bind-mount ไดเรกทอรีซอร์สของ Plugin ทับพาธซอร์สที่แพ็กเกจไว้ให้ตรงกัน เช่น `/app/extensions/synology-chat` OpenClaw จะค้นพบ source overlay ที่ mount นั้นก่อน `/app/dist/extensions/synology-chat`; ไดเรกทอรีซอร์สที่คัดลอกธรรมดาจะยังไม่ทำงาน เพื่อให้การติดตั้งแบบแพ็กเกจปกติยังใช้ dist ที่คอมไพล์แล้ว +สำหรับงาน Plugin ที่บันเดิลอยู่ภายในอิมเมจ Docker แบบแพ็กเกจ ให้ bind-mount ไดเรกทอรีต้นทางของ Plugin ทับพาธต้นทางแบบแพ็กเกจที่ตรงกัน เช่น `/app/extensions/synology-chat` OpenClaw จะค้นพบ overlay ต้นทางที่ mount นั้นก่อน `/app/dist/extensions/synology-chat`; ไดเรกทอรีต้นทางที่คัดลอกธรรมดาจะไม่ทำงาน ดังนั้นการติดตั้งแบบแพ็กเกจปกติยังคงใช้ dist ที่คอมไพล์แล้ว -สำหรับการดีบัก runtime hook: +สำหรับการ debug hook ขณะรันไทม์: -- `openclaw plugins inspect --runtime --json` แสดง hook ที่ลงทะเบียนและ diagnostics จากรอบการตรวจสอบที่โหลดโมดูล การตรวจสอบ runtime จะไม่ติดตั้ง dependency; ใช้ `openclaw doctor --fix` เพื่อล้างสถานะ dependency เก่าหรือติดตั้ง Plugin ที่ดาวน์โหลดได้ซึ่งกำหนดค่าไว้แต่ขาดหาย +- `openclaw plugins inspect --runtime --json` แสดง hook ที่ลงทะเบียนแล้วและ diagnostics จากรอบ inspection ที่โหลด module แล้ว Runtime inspection ไม่เคยติดตั้ง dependency; ใช้ `openclaw doctor --fix` เพื่อล้างสถานะ dependency แบบ legacy หรือติดตั้ง Plugin ที่ดาวน์โหลดได้ซึ่งกำหนดค่าไว้แต่หายไป - `openclaw gateway status --deep --require-rpc` ยืนยัน Gateway ที่เข้าถึงได้, คำใบ้ service/process, พาธ config และสุขภาพ RPC -- hook การสนทนาที่ไม่ได้บันเดิล (`llm_input`, `llm_output`, `before_agent_finalize`, `agent_end`) ต้องใช้ `plugins.entries..hooks.allowConversationAccess=true` +- hook การสนทนาที่ไม่ใช่แบบบันเดิล (`llm_input`, `llm_output`, `before_agent_finalize`, `agent_end`) ต้องใช้ `plugins.entries..hooks.allowConversationAccess=true` ใช้ `--link` เพื่อหลีกเลี่ยงการคัดลอกไดเรกทอรีในเครื่อง (เพิ่มเข้า `plugins.load.paths`): @@ -264,16 +274,16 @@ openclaw plugins install -l ./my-plugin ``` -`--force` ไม่รองรับร่วมกับ `--link` เพราะการติดตั้งแบบลิงก์จะใช้พาธซอร์สซ้ำแทนการคัดลอกทับเป้าหมายการติดตั้งที่จัดการอยู่ +ไม่รองรับ `--force` ร่วมกับ `--link` เพราะการติดตั้งแบบ linked ใช้พาธต้นทางซ้ำแทนการคัดลอกทับเป้าหมายการติดตั้งที่จัดการโดยระบบ -ใช้ `--pin` กับการติดตั้ง npm เพื่อบันทึก spec ที่ resolve แล้วแบบแน่นอน (`name@version`) ในดัชนี Plugin ที่จัดการอยู่ ขณะที่ยังคงพฤติกรรมเริ่มต้นแบบไม่ pin +ใช้ `--pin` กับการติดตั้ง npm เพื่อบันทึก spec แบบ exact ที่ resolve แล้ว (`name@version`) ในดัชนี Plugin ที่จัดการโดยระบบ ขณะที่พฤติกรรมเริ่มต้นยังคงไม่ pin ### ดัชนี Plugin -เมทาดาทาการติดตั้ง Plugin เป็นสถานะที่เครื่องจัดการ ไม่ใช่ config ของผู้ใช้ การติดตั้งและอัปเดตจะเขียนข้อมูลนี้ไปยัง `plugins/installs.json` ใต้ไดเรกทอรีสถานะ OpenClaw ที่ใช้งานอยู่ map ระดับบนสุด `installRecords` เป็นแหล่งข้อมูลถาวรของเมทาดาทาการติดตั้ง รวมถึงระเบียนสำหรับ manifest ของ Plugin ที่เสียหรือขาดหาย อาร์เรย์ `plugins` เป็นแคช cold registry ที่สร้างจาก manifest ไฟล์นี้มีคำเตือนห้ามแก้ไข และถูกใช้โดย `openclaw plugins update`, uninstall, diagnostics และ cold plugin registry +metadata การติดตั้ง Plugin เป็นสถานะที่เครื่องจัดการ ไม่ใช่ config ของผู้ใช้ การติดตั้งและอัปเดตจะเขียนไปยัง `plugins/installs.json` ภายใต้ไดเรกทอรีสถานะ OpenClaw ที่ใช้งานอยู่ map ระดับบนสุด `installRecords` คือแหล่งข้อมูลถาวรของ metadata การติดตั้ง รวมถึง record สำหรับ manifest ของ Plugin ที่เสียหรือหายไป array `plugins` คือแคช registry แบบ cold ที่ derive จาก manifest ไฟล์นี้มีคำเตือนห้ามแก้ไข และถูกใช้โดย `openclaw plugins update`, uninstall, diagnostics และ registry ของ Plugin แบบ cold -เมื่อ OpenClaw พบระเบียน `plugins.installs` แบบ legacy ที่มากับระบบใน config จะย้ายระเบียนเหล่านั้นไปยังดัชนี Plugin และลบคีย์ config ออก หากการเขียนอย่างใดอย่างหนึ่งล้มเหลว ระเบียน config จะถูกเก็บไว้เพื่อไม่ให้เมทาดาทาการติดตั้งสูญหาย +เมื่อ OpenClaw พบ record `plugins.installs` แบบ legacy ที่เคยจัดส่งใน config จะย้าย record เหล่านั้นเข้าไปในดัชนี Plugin และลบ config key ออก หากการเขียนครั้งใดครั้งหนึ่งล้มเหลว record ใน config จะถูกเก็บไว้เพื่อไม่ให้ metadata การติดตั้งสูญหาย ### ถอนการติดตั้ง @@ -283,7 +293,7 @@ openclaw plugins uninstall --dry-run openclaw plugins uninstall --keep-files ``` -`uninstall` ลบระเบียน Plugin ออกจาก `plugins.entries`, ดัชนี Plugin ที่คงอยู่, รายการ allow/deny ของ Plugin และรายการ `plugins.load.paths` ที่ลิงก์ไว้เมื่อเกี่ยวข้อง เว้นแต่ตั้งค่า `--keep-files` การถอนการติดตั้งจะลบไดเรกทอรีการติดตั้งที่จัดการและติดตามไว้ด้วยเมื่อไดเรกทอรีนั้นอยู่ภายในรูท extensions ของ Plugin ของ OpenClaw สำหรับ Plugin หน่วยความจำที่ใช้งานอยู่ slot หน่วยความจำจะรีเซ็ตเป็น `memory-core` +`uninstall` ลบ record ของ Plugin ออกจาก `plugins.entries`, ดัชนี Plugin ที่ persisted ไว้, รายการ allow/deny ของ Plugin และรายการ linked `plugins.load.paths` เมื่อเกี่ยวข้อง เว้นแต่ตั้งค่า `--keep-files` ไว้ uninstall ยังลบไดเรกทอรีการติดตั้งที่จัดการโดยระบบซึ่งติดตามไว้ เมื่อไดเรกทอรีนั้นอยู่ภายในราก extensions ของ Plugin ของ OpenClaw สำหรับ Plugin หน่วยความจำ active memory slot จะรีเซ็ตเป็น `memory-core` รองรับ `--keep-config` เป็น alias ที่เลิกใช้แล้วของ `--keep-files` @@ -299,33 +309,33 @@ openclaw plugins update @openclaw/voice-call openclaw plugins update openclaw-codex-app-server --dangerously-force-unsafe-install ``` -การอัปเดตใช้กับการติดตั้ง Plugin ที่ติดตามไว้ในดัชนี Plugin ที่จัดการอยู่ และการติดตั้ง hook-pack ที่ติดตามไว้ใน `hooks.internal.installs` +การอัปเดตมีผลกับการติดตั้ง Plugin ที่ติดตามไว้ในดัชนี Plugin ที่จัดการโดยระบบ และการติดตั้ง hook-pack ที่ติดตามไว้ใน `hooks.internal.installs` - - เมื่อคุณส่ง id ของ Plugin OpenClaw จะใช้ spec การติดตั้งที่บันทึกไว้สำหรับ Plugin นั้นซ้ำ ซึ่งหมายความว่า dist-tag ที่เคยจัดเก็บไว้ เช่น `@beta` และเวอร์ชันที่ pin แบบแน่นอน จะยังถูกใช้ต่อในการรัน `update ` ภายหลัง + + เมื่อคุณส่ง id ของ Plugin OpenClaw จะใช้ spec การติดตั้งที่บันทึกไว้สำหรับ Plugin นั้นซ้ำ นั่นหมายความว่า dist-tag ที่เคยจัดเก็บไว้ เช่น `@beta` และเวอร์ชัน exact ที่ pin ไว้จะยังคงถูกใช้ในการรัน `update ` ภายหลัง - สำหรับการติดตั้ง npm คุณยังสามารถส่ง npm package spec แบบชัดเจนพร้อม dist-tag หรือเวอร์ชันแน่นอนได้ด้วย OpenClaw จะ resolve ชื่อแพ็กเกจนั้นกลับไปยังระเบียน Plugin ที่ติดตามไว้ อัปเดต Plugin ที่ติดตั้งนั้น และบันทึก npm spec ใหม่สำหรับการอัปเดตตาม id ในอนาคต + สำหรับการติดตั้ง npm คุณยังสามารถส่ง spec ของ package npm แบบ explicit พร้อม dist-tag หรือเวอร์ชัน exact ได้ OpenClaw จะ resolve ชื่อ package นั้นกลับไปยัง record ของ Plugin ที่ติดตามไว้ อัปเดต Plugin ที่ติดตั้งนั้น และบันทึก spec npm ใหม่สำหรับการอัปเดตตาม id ในอนาคต - การส่งชื่อแพ็กเกจ npm โดยไม่มีเวอร์ชันหรือแท็กก็จะ resolve กลับไปยังระเบียน Plugin ที่ติดตามไว้เช่นกัน ใช้วิธีนี้เมื่อ Plugin ถูก pin ไว้ที่เวอร์ชันแน่นอน และคุณต้องการย้ายกลับไปยังสาย release เริ่มต้นของ registry + การส่งชื่อ package npm โดยไม่มีเวอร์ชันหรือ tag ก็ resolve กลับไปยัง record ของ Plugin ที่ติดตามไว้เช่นกัน ใช้วิธีนี้เมื่อ Plugin ถูก pin ไว้กับเวอร์ชัน exact และคุณต้องการย้ายกลับไปยัง release line เริ่มต้นของ registry - `openclaw plugins update` ใช้ spec ของ Plugin ที่ติดตามไว้ซ้ำ เว้นแต่คุณจะส่ง spec ใหม่ `openclaw update` ยังรู้จัก channel อัปเดต OpenClaw ที่ใช้งานอยู่เพิ่มเติม: บน channel beta ระเบียน Plugin จาก npm และ ClawHub ในสายเริ่มต้นจะลอง `@beta` ก่อน แล้วจึง fallback ไปยัง spec default/latest ที่บันทึกไว้หากไม่มี release beta ของ Plugin เวอร์ชันแน่นอนและแท็กที่ระบุชัดเจนจะยังคง pin กับตัวเลือกนั้น + `openclaw plugins update` ใช้ spec ของ Plugin ที่ติดตามไว้ซ้ำ เว้นแต่คุณจะส่ง spec ใหม่ `openclaw update` ยังรู้จัก channel การอัปเดต OpenClaw ที่ใช้งานอยู่เพิ่มเติม: บน channel beta, record ของ Plugin จาก npm และ ClawHub ใน default-line จะลอง `@beta` ก่อน แล้ว fallback ไปยัง spec default/latest ที่บันทึกไว้หากไม่มี release beta ของ Plugin เวอร์ชัน exact และ tag explicit จะยังคง pin อยู่กับ selector นั้น - ก่อนการอัปเดต npm แบบสด OpenClaw จะตรวจสอบเวอร์ชันแพ็กเกจที่ติดตั้งเทียบกับเมทาดาทา registry ของ npm หากเวอร์ชันที่ติดตั้งและอัตลักษณ์ artifact ที่บันทึกไว้ตรงกับเป้าหมายที่ resolve แล้วอยู่แล้ว การอัปเดตจะถูกข้ามโดยไม่ดาวน์โหลด, ติดตั้งใหม่ หรือเขียน `openclaw.json` ใหม่ + ก่อนการอัปเดต npm แบบสด OpenClaw ตรวจสอบเวอร์ชัน package ที่ติดตั้งกับ metadata ของ npm registry หากเวอร์ชันที่ติดตั้งและ identity ของ artifact ที่บันทึกไว้ตรงกับ target ที่ resolve แล้ว การอัปเดตจะถูกข้ามโดยไม่ดาวน์โหลด ติดตั้งซ้ำ หรือเขียน `openclaw.json` ใหม่ - เมื่อมี hash integrity ที่จัดเก็บไว้และ hash ของ artifact ที่ดึงมาเปลี่ยนแปลง OpenClaw จะถือว่านั่นเป็น npm artifact drift คำสั่ง `openclaw plugins update` แบบโต้ตอบจะพิมพ์ hash ที่คาดหวังและ hash จริง แล้วขอการยืนยันก่อนดำเนินการต่อ ตัวช่วยอัปเดตแบบไม่โต้ตอบจะปิดแบบล้มเหลว เว้นแต่ caller จะระบุ policy การดำเนินการต่ออย่างชัดเจน + เมื่อมี integrity hash ที่จัดเก็บไว้และ hash ของ artifact ที่ fetch มาเปลี่ยนไป OpenClaw จะถือว่านั่นคือ npm artifact drift คำสั่ง interactive `openclaw plugins update` จะพิมพ์ hash ที่คาดหวังและ hash จริง แล้วขอการยืนยันก่อนดำเนินการต่อ helper อัปเดตแบบ non-interactive จะ fail closed เว้นแต่ caller จะระบุนโยบาย continuation แบบ explicit - - `--dangerously-force-unsafe-install` ยังใช้ได้กับ `plugins update` ในฐานะ override ฉุกเฉินสำหรับ false positive ของการสแกน dangerous-code ในตัวระหว่างการอัปเดต Plugin แต่ยังไม่ข้าม policy block `before_install` ของ Plugin หรือการบล็อกเมื่อการสแกนล้มเหลว และใช้กับการอัปเดต Plugin เท่านั้น ไม่ใช่การอัปเดต hook-pack + + `--dangerously-force-unsafe-install` ยังใช้ได้บน `plugins update` เป็น override แบบ break-glass สำหรับ false positive จากการสแกน dangerous-code ในตัวระหว่างอัปเดต Plugin แต่ยังไม่ข้ามการบล็อกตามนโยบาย `before_install` ของ Plugin หรือการบล็อกเมื่อสแกนล้มเหลว และมีผลกับการอัปเดต Plugin เท่านั้น ไม่ใช่การอัปเดต hook-pack -### ตรวจสอบ +### ตรวจสอบรายละเอียด ```bash openclaw plugins inspect @@ -333,21 +343,21 @@ openclaw plugins inspect --runtime openclaw plugins inspect --json ``` -Inspect แสดง identity, สถานะการโหลด, source, ความสามารถของ manifest, policy flags, diagnostics, เมทาดาทาการติดตั้ง, ความสามารถของบันเดิล และการรองรับ MCP หรือ LSP server ที่ตรวจพบ โดยค่าเริ่มต้นจะไม่นำเข้า runtime ของ Plugin เพิ่ม `--runtime` เพื่อโหลดโมดูล Plugin และรวม hook, tools, commands, services, gateway methods และ HTTP routes ที่ลงทะเบียนไว้ การตรวจสอบ runtime จะรายงาน dependency ของ Plugin ที่ขาดหายโดยตรง; การติดตั้งและซ่อมแซมยังอยู่ใน `openclaw plugins install`, `openclaw plugins update` และ `openclaw doctor --fix` +Inspect แสดง identity, สถานะการโหลด, source, ความสามารถจาก manifest, policy flags, diagnostics, metadata การติดตั้ง, ความสามารถของบันเดิล และการรองรับ server MCP หรือ LSP ใด ๆ ที่ตรวจพบ โดยค่าเริ่มต้นจะไม่ import รันไทม์ของ Plugin เพิ่ม `--runtime` เพื่อโหลด module ของ Plugin และรวม hook, tools, commands, services, gateway methods และ HTTP routes ที่ลงทะเบียนไว้ Runtime inspection รายงาน dependency ของ Plugin ที่หายไปโดยตรง; การติดตั้งและการซ่อมยังคงอยู่ใน `openclaw plugins install`, `openclaw plugins update` และ `openclaw doctor --fix` -คำสั่ง CLI ที่ Plugin เป็นเจ้าของจะติดตั้งเป็นกลุ่มคำสั่งราก `openclaw` หลังจาก `inspect --runtime` แสดงคำสั่งใต้ `cliCommands` แล้ว ให้รันเป็น `openclaw ...`; เช่น Plugin ที่ลงทะเบียน `demo-git` สามารถตรวจสอบได้ด้วย `openclaw demo-git ping` +คำสั่ง CLI ที่ Plugin เป็นเจ้าของจะติดตั้งเป็นกลุ่มคำสั่ง root `openclaw` หลังจาก `inspect --runtime` แสดงคำสั่งใต้ `cliCommands` ให้รันเป็น `openclaw ...`; ตัวอย่างเช่น Plugin ที่ลงทะเบียน `demo-git` สามารถตรวจสอบได้ด้วย `openclaw demo-git ping` -Plugin แต่ละตัวจะถูกจัดประเภทตามสิ่งที่ลงทะเบียนจริงใน runtime: +แต่ละ Plugin ถูกจัดประเภทตามสิ่งที่ลงทะเบียนจริงขณะรันไทม์: -- **plain-capability** — ความสามารถหนึ่งประเภท (เช่น Plugin ที่เป็น provider อย่างเดียว) -- **hybrid-capability** — ความสามารถหลายประเภท (เช่น ข้อความ + เสียงพูด + รูปภาพ) +- **plain-capability** — ความสามารถหนึ่งประเภท (เช่น Plugin เฉพาะ provider) +- **hybrid-capability** — ความสามารถหลายประเภท (เช่น text + speech + images) - **hook-only** — เฉพาะ hook ไม่มีความสามารถหรือ surface - **non-capability** — tools/commands/services แต่ไม่มีความสามารถ -ดู [รูปทรง Plugin](/th/plugins/architecture#plugin-shapes) สำหรับข้อมูลเพิ่มเติมเกี่ยวกับโมเดลความสามารถ +ดู [รูปแบบ Plugin](/th/plugins/architecture#plugin-shapes) สำหรับข้อมูลเพิ่มเติมเกี่ยวกับโมเดลความสามารถ -แฟล็ก `--json` ส่งออกรายงานที่เครื่องอ่านได้ เหมาะสำหรับสคริปต์และการ audit `inspect --all` จะแสดงตารางทั้ง fleet พร้อมคอลัมน์ shape, capability kinds, compatibility notices, bundle capabilities และ hook summary `info` เป็น alias ของ `inspect` +flag `--json` ส่งออกรายงานที่เครื่องอ่านได้ เหมาะสำหรับ scripting และ auditing `inspect --all` แสดงตารางครอบคลุมทั้ง fleet พร้อมคอลัมน์ shape, capability kinds, compatibility notices, bundle capabilities และ hook summary `info` เป็น alias ของ `inspect` ### Doctor @@ -356,11 +366,11 @@ Plugin แต่ละตัวจะถูกจัดประเภทตา openclaw plugins doctor ``` -`doctor` รายงานข้อผิดพลาดในการโหลด Plugin, diagnostics ของ manifest/discovery และ compatibility notices เมื่อทุกอย่างสะอาด จะพิมพ์ `No plugin issues detected.` +`doctor` รายงานข้อผิดพลาดการโหลด Plugin, diagnostics ของ manifest/discovery และ compatibility notices เมื่อทุกอย่างสะอาดจะแสดง `No plugin issues detected.` -หาก Plugin ที่กำหนดค่าไว้มีอยู่บนดิสก์แต่ถูกบล็อกโดยการตรวจ path-safety ของ loader การตรวจสอบ config จะเก็บรายการ Plugin ไว้และรายงานเป็น `present but blocked` ให้แก้ diagnostic ของ Plugin ที่ถูกบล็อกก่อนหน้า เช่น ownership ของพาธหรือ permission แบบ world-writable แทนการลบ config `plugins.entries.` หรือ `plugins.allow` +หาก Plugin ที่กำหนดค่าไว้มีอยู่บนดิสก์แต่ถูกบล็อกโดยการตรวจสอบ path-safety ของ loader การ validate config จะเก็บรายการ Plugin ไว้และรายงานเป็น `present but blocked` ให้แก้ diagnostic ของ Plugin ที่ถูกบล็อกก่อนหน้า เช่น ownership ของพาธหรือ permission แบบ world-writable แทนที่จะลบ config `plugins.entries.` หรือ `plugins.allow` -สำหรับความล้มเหลวของรูปทรงโมดูล เช่น export `register`/`activate` ที่ขาดหาย ให้รันซ้ำด้วย `OPENCLAW_PLUGIN_LOAD_DEBUG=1` เพื่อรวมสรุปรูปทรง export แบบกระชับไว้ในเอาต์พุต diagnostic +สำหรับความล้มเหลวของ module-shape เช่น export `register`/`activate` หายไป ให้รันซ้ำด้วย `OPENCLAW_PLUGIN_LOAD_DEBUG=1` เพื่อรวมสรุป export-shape แบบกระชับใน output diagnostics ### Registry @@ -370,25 +380,25 @@ openclaw plugins registry --refresh openclaw plugins registry --json ``` -registry Plugin ในเครื่องคือโมเดลอ่านแบบเย็นที่คงอยู่ของ OpenClaw สำหรับ identity ของ Plugin ที่ติดตั้ง, enablement, เมทาดาทา source และ ownership ของ contribution การเริ่มต้นปกติ, การค้นหาเจ้าของ provider, การจำแนก channel setup และ inventory ของ Plugin สามารถอ่านข้อมูลนี้ได้โดยไม่ต้องนำเข้าโมดูล runtime ของ Plugin +registry ของ Plugin ในเครื่องคือโมเดลอ่านแบบ cold ที่ persisted ไว้ของ OpenClaw สำหรับ identity ของ Plugin ที่ติดตั้ง, enablement, metadata ของ source และ ownership ของ contribution การ startup ปกติ, การ lookup เจ้าของ provider, การจัดประเภท setup ของ channel และ inventory ของ Plugin สามารถอ่านได้โดยไม่ต้อง import module รันไทม์ของ Plugin -ใช้ `plugins registry` เพื่อตรวจสอบว่ารีจิสทรีที่จัดเก็บไว้มีอยู่ เป็นปัจจุบัน หรือล้าสมัย ใช้ `--refresh` เพื่อสร้างใหม่จากดัชนี Plugin ที่จัดเก็บไว้ นโยบายการกำหนดค่า และเมทาดาทา manifest/package นี่คือเส้นทางการซ่อมแซม ไม่ใช่เส้นทางการเปิดใช้งานขณะรันไทม์ +ใช้ `plugins registry` เพื่อตรวจสอบว่า registry ที่บันทึกไว้มีอยู่ เป็นปัจจุบัน หรือล้าสมัย ใช้ `--refresh` เพื่อสร้างใหม่จากดัชนี Plugin ที่บันทึกไว้ นโยบาย config และเมทาดาทา manifest/package นี่เป็นเส้นทางสำหรับการซ่อมแซม ไม่ใช่เส้นทางสำหรับการเปิดใช้งานขณะรันไทม์ -`OPENCLAW_DISABLE_PERSISTED_PLUGIN_REGISTRY=1` เป็นสวิตช์ความเข้ากันได้แบบฉุกเฉินที่เลิกใช้แล้วสำหรับความล้มเหลวในการอ่านรีจิสทรี ควรใช้ `plugins registry --refresh` หรือ `openclaw doctor --fix`; กลไกสำรองผ่าน env มีไว้สำหรับการกู้คืนการเริ่มต้นระบบฉุกเฉินเท่านั้นระหว่างที่การย้ายระบบกำลังทยอยใช้งาน +`OPENCLAW_DISABLE_PERSISTED_PLUGIN_REGISTRY=1` เป็นสวิตช์ความเข้ากันได้แบบ break-glass ที่เลิกใช้แล้วสำหรับความล้มเหลวในการอ่าน registry ควรใช้ `plugins registry --refresh` หรือ `openclaw doctor --fix`; fallback ผ่าน env มีไว้สำหรับการกู้คืนการเริ่มต้นในกรณีฉุกเฉินเท่านั้นระหว่างที่การย้ายระบบกำลังทยอยใช้งาน -### มาร์เก็ตเพลส +### Marketplace ```bash openclaw plugins marketplace list openclaw plugins marketplace list --json ``` -รายการมาร์เก็ตเพลสรับพาธมาร์เก็ตเพลสภายในเครื่อง, พาธ `marketplace.json`, รูปย่อ GitHub เช่น `owner/repo`, URL ของ repo GitHub หรือ URL git `--json` จะพิมพ์ป้ายกำกับแหล่งที่มาที่แก้ไขแล้ว พร้อมกับ manifest ของมาร์เก็ตเพลสที่แยกวิเคราะห์แล้วและรายการ Plugin +รายการ Marketplace รองรับพาธ Marketplace ในเครื่อง, พาธ `marketplace.json`, รูปย่อ GitHub เช่น `owner/repo`, URL repo ของ GitHub หรือ URL git `--json` จะแสดงป้ายกำกับแหล่งที่มาที่ resolve แล้ว พร้อม manifest ของ Marketplace ที่แยกวิเคราะห์แล้วและรายการ Plugin ## ที่เกี่ยวข้อง - [การสร้าง Plugin](/th/plugins/building-plugins) - [ข้อมูลอ้างอิง CLI](/th/cli) -- [Plugin ชุมชน](/th/plugins/community) +- [Plugin จากชุมชน](/th/plugins/community) diff --git a/docs/th/cli/proxy.md b/docs/th/cli/proxy.md index fa12b430e..d0d194d67 100644 --- a/docs/th/cli/proxy.md +++ b/docs/th/cli/proxy.md @@ -1,29 +1,29 @@ --- read_when: - - คุณต้องตรวจสอบความถูกต้องของการกำหนดเส้นทางพร็อกซีที่ผู้ปฏิบัติงานจัดการก่อนการปรับใช้ - - คุณต้องจับทราฟฟิกการรับส่งข้อมูลของ OpenClaw ในเครื่องเพื่อการดีบัก - - คุณต้องการตรวจสอบเซสชันพร็อกซีดีบัก บล็อบ หรือค่าพรีเซ็ตการสืบค้นในตัว -summary: ข้อมูลอ้างอิง CLI สำหรับ `openclaw proxy` รวมถึงการตรวจสอบความถูกต้องของพร็อกซีที่ผู้ปฏิบัติงานจัดการ และตัวตรวจสอบการจับข้อมูลพร็อกซีดีบักภายในเครื่อง + - คุณต้องตรวจสอบยืนยันการกำหนดเส้นทางพร็อกซีที่ผู้ปฏิบัติการจัดการก่อนการปรับใช้ + - คุณต้องจับทราฟฟิกการรับส่งข้อมูลของ OpenClaw ภายในเครื่องเพื่อการดีบัก + - คุณต้องการตรวจสอบเซสชันพร็อกซีดีบัก บล็อบ หรือพรีเซ็ตคิวรีในตัว +summary: ข้อมูลอ้างอิง CLI สำหรับ `openclaw proxy` รวมถึงการตรวจสอบพร็อกซีที่จัดการโดยผู้ปฏิบัติการและตัวตรวจสอบการจับพร็อกซีดีบักภายในเครื่อง title: พร็อกซี x-i18n: - generated_at: "2026-05-01T10:15:34Z" + generated_at: "2026-05-04T07:03:12Z" model: gpt-5.5 provider: openai - source_hash: e0820de861bfe1ec14e0c1624d636d6474b5fedd317e3ba1baaa61f6530e06e9 + source_hash: 9589bedafb97c31bcb6536a04307cd0c6550e1f307693bd4401785d79f34a1eb source_path: cli/proxy.md workflow: 16 --- # `openclaw proxy` -ตรวจสอบความถูกต้องของการกำหนดเส้นทางพร็อกซีที่จัดการโดยผู้ปฏิบัติการ หรือเรียกใช้พร็อกซีดีบักแบบชัดเจนในเครื่อง -และตรวจดูทราฟฟิกที่จับบันทึกไว้ +ตรวจสอบความถูกต้องของการกำหนดเส้นทางพร็อกซีที่ผู้ปฏิบัติงานจัดการ หรือเรียกใช้พร็อกซีดีบักแบบระบุชัดภายในเครื่อง +และตรวจสอบทราฟฟิกที่บันทึกไว้ -ใช้ `validate` เพื่อ preflight พร็อกซีส่งต่อที่จัดการโดยผู้ปฏิบัติการก่อนเปิดใช้ +ใช้ `validate` เพื่อตรวจสอบล่วงหน้าพร็อกซีส่งต่อที่ผู้ปฏิบัติงานจัดการก่อนเปิดใช้ การกำหนดเส้นทางพร็อกซีของ OpenClaw คำสั่งอื่นเป็นเครื่องมือดีบักสำหรับ -การตรวจสอบระดับทรานสปอร์ต: สามารถเริ่มพร็อกซีในเครื่อง เรียกใช้คำสั่งลูก -โดยเปิดการจับบันทึก แสดงรายการเซสชันการจับบันทึก คิวรีรูปแบบทราฟฟิกทั่วไป อ่าน -บล็อบที่จับบันทึกไว้ และล้างข้อมูลการจับบันทึกในเครื่อง +การตรวจสอบในระดับการขนส่ง: สามารถเริ่มพร็อกซีภายในเครื่อง เรียกใช้คำสั่งลูก +พร้อมเปิดการบันทึก แสดงรายการเซสชันการบันทึก ค้นหารูปแบบทราฟฟิกทั่วไป อ่าน +บล็อบที่บันทึกไว้ และล้างข้อมูลการบันทึกภายในเครื่อง ## คำสั่ง @@ -40,29 +40,29 @@ openclaw proxy purge ## ตรวจสอบความถูกต้อง -`openclaw proxy validate` ตรวจสอบ URL พร็อกซีที่จัดการโดยผู้ปฏิบัติการซึ่งมีผลใช้งานจริงจาก -`--proxy-url`, คอนฟิก หรือ `OPENCLAW_PROXY_URL` โดยจะรายงานปัญหาคอนฟิกเมื่อ -ไม่มีพร็อกซีที่เปิดใช้และกำหนดค่าไว้; ใช้ `--proxy-url` สำหรับการ preflight แบบครั้งเดียว -ก่อนเปลี่ยนคอนฟิก ตามค่าเริ่มต้น คำสั่งนี้จะตรวจสอบว่าปลายทางสาธารณะสำเร็จ -ผ่านพร็อกซี และพร็อกซีไม่สามารถเข้าถึง canary แบบลูปแบ็กชั่วคราวได้ -ปลายทางที่กำหนดเองว่าควรถูกปฏิเสธจะเป็นแบบ fail-closed: การตอบกลับ HTTP และความล้มเหลว -ของทรานสปอร์ตที่กำกวมจะถือว่าล้มเหลวทั้งคู่ เว้นแต่คุณจะสามารถตรวจสอบสัญญาณการปฏิเสธ -เฉพาะการติดตั้งใช้งานแยกต่างหากได้ +`openclaw proxy validate` ตรวจสอบ URL พร็อกซีที่ผู้ปฏิบัติงานจัดการซึ่งมีผลใช้งาน จาก +`--proxy-url`, การกำหนดค่า หรือ `OPENCLAW_PROXY_URL` โดยรายงานปัญหาการกำหนดค่าเมื่อ +ไม่มีพร็อกซีที่เปิดใช้งานและกำหนดค่าไว้ ใช้ `--proxy-url` สำหรับการตรวจสอบล่วงหน้าแบบครั้งเดียว +ก่อนเปลี่ยนการกำหนดค่า โดยค่าเริ่มต้น ระบบจะตรวจสอบว่าปลายทางสาธารณะสำเร็จ +ผ่านพร็อกซี และพร็อกซีไม่สามารถเข้าถึงคานารี loopback ชั่วคราวได้ +ปลายทางที่กำหนดเองซึ่งคาดว่าจะถูกปฏิเสธจะปิดเมื่อไม่ผ่าน: การตอบกลับ HTTP และความล้มเหลว +ของการขนส่งที่กำกวมจะถือว่าไม่ผ่านทั้งคู่ เว้นแต่คุณจะสามารถตรวจสอบสัญญาณการปฏิเสธ +เฉพาะการปรับใช้แยกต่างหากได้ ตัวเลือก: - `--json`: พิมพ์ JSON ที่เครื่องอ่านได้ -- `--proxy-url `: ตรวจสอบความถูกต้องของ URL พร็อกซีนี้แทนคอนฟิกหรือ env -- `--allowed-url `: เพิ่มปลายทางที่คาดว่าจะสำเร็จผ่านพร็อกซี ทำซ้ำเพื่อเช็กหลายปลายทาง -- `--denied-url `: เพิ่มปลายทางที่คาดว่าจะถูกพร็อกซีบล็อก ทำซ้ำเพื่อเช็กหลายปลายทาง -- `--timeout-ms `: เวลาหมดเวลาต่อคำขอ หน่วยเป็นมิลลิวินาที +- `--proxy-url `: ตรวจสอบ URL พร็อกซีนี้แทนการกำหนดค่าหรือตัวแปรสภาพแวดล้อม +- `--allowed-url `: เพิ่มปลายทางที่คาดว่าจะสำเร็จผ่านพร็อกซี ทำซ้ำเพื่อตรวจสอบหลายปลายทาง +- `--denied-url `: เพิ่มปลายทางที่คาดว่าจะถูกพร็อกซีบล็อก ทำซ้ำเพื่อตรวจสอบหลายปลายทาง +- `--timeout-ms `: ระยะหมดเวลาต่อคำขอ หน่วยเป็นมิลลิวินาที -ดู [พร็อกซีเครือข่าย](/th/security/network-proxy) สำหรับคำแนะนำการติดตั้งใช้งานและความหมาย +ดู [พร็อกซีเครือข่าย](/th/security/network-proxy) สำหรับแนวทางการปรับใช้และความหมาย ของการปฏิเสธ -## พรีเซ็ตคิวรี +## พรีเซ็ตการค้นหา -`openclaw proxy query --preset ` รับค่า: +`openclaw proxy query --preset ` ยอมรับ: - `double-sends` - `retry-storms` @@ -73,13 +73,14 @@ openclaw proxy purge ## หมายเหตุ -- `start` มีค่าเริ่มต้นเป็น `127.0.0.1` เว้นแต่จะตั้งค่า `--host` -- `run` เริ่มพร็อกซีดีบักในเครื่อง แล้วจึงเรียกใช้คำสั่งหลัง `--` -- `validate` ออกด้วยรหัส 1 เมื่อคอนฟิกพร็อกซีหรือการตรวจสอบปลายทางล้มเหลว -- การจับบันทึกเป็นข้อมูลดีบักในเครื่อง; ใช้ `openclaw proxy purge` เมื่อเสร็จสิ้น +- `start` ใช้ค่าเริ่มต้นเป็น `127.0.0.1` เว้นแต่จะตั้งค่า `--host` +- `run` เริ่มพร็อกซีดีบักภายในเครื่องแล้วจึงเรียกใช้คำสั่งหลัง `--` +- การส่งต่อไปยังต้นทางโดยตรงของพร็อกซีดีบักจะเปิดซ็อกเก็ตต้นทางเพื่อการวินิจฉัย เมื่อโหมดพร็อกซีที่ OpenClaw จัดการเปิดใช้งานอยู่ การส่งต่อโดยตรงสำหรับคำขอพร็อกซีและอุโมงค์ CONNECT จะถูกปิดใช้งานตามค่าเริ่มต้น ตั้งค่า `OPENCLAW_DEBUG_PROXY_ALLOW_DIRECT_CONNECT_WITH_MANAGED_PROXY=1` เฉพาะสำหรับการวินิจฉัยภายในเครื่องที่ได้รับอนุมัติแล้วเท่านั้น +- `validate` ออกด้วยรหัส 1 เมื่อการกำหนดค่าพร็อกซีหรือการตรวจสอบปลายทางล้มเหลว +- การบันทึกเป็นข้อมูลดีบักภายในเครื่อง ใช้ `openclaw proxy purge` เมื่อดำเนินการเสร็จ ## ที่เกี่ยวข้อง -- [เอกสารอ้างอิง CLI](/th/cli) +- [อ้างอิง CLI](/th/cli) - [พร็อกซีเครือข่าย](/th/security/network-proxy) -- [การตรวจสอบสิทธิ์พร็อกซีที่เชื่อถือได้](/th/gateway/trusted-proxy-auth) +- [การยืนยันตัวตนของพร็อกซีที่เชื่อถือได้](/th/gateway/trusted-proxy-auth) diff --git a/docs/th/cli/sessions.md b/docs/th/cli/sessions.md index d9bd5bec2..b91a29451 100644 --- a/docs/th/cli/sessions.md +++ b/docs/th/cli/sessions.md @@ -1,13 +1,13 @@ --- read_when: - - คุณต้องการแสดงรายการเซสชันที่จัดเก็บไว้และดูกิจกรรมล่าสุด -summary: ข้อมูลอ้างอิง CLI สำหรับ `openclaw sessions` (แสดงรายการเซสชันที่จัดเก็บไว้ + การใช้งาน) + - คุณต้องการแสดงรายการเซสชันที่บันทึกไว้และดูกิจกรรมล่าสุด +summary: เอกสารอ้างอิง CLI สำหรับ `openclaw sessions` (แสดงรายการเซสชันที่จัดเก็บไว้ + การใช้งาน) title: เซสชัน x-i18n: - generated_at: "2026-05-02T20:42:28Z" + generated_at: "2026-05-04T07:02:48Z" model: gpt-5.5 provider: openai - source_hash: 5c9ec3ca55f7c5b6217b481e9da62f5416df73e69405a0dc15e77d2afeac723f + source_hash: 8dc90344f40c53513bd6db3696bc709279155f26e7c3b6ea27e81a07a2f9f15e source_path: cli/sessions.md workflow: 16 --- @@ -16,7 +16,9 @@ x-i18n: แสดงรายการเซสชันการสนทนาที่จัดเก็บไว้ -รายการเซสชันไม่ใช่การตรวจสอบว่าช่องทาง/ผู้ให้บริการยังเชื่อมต่ออยู่หรือไม่ รายการเหล่านี้แสดงแถวการสนทนาที่บันทึกถาวรจากที่จัดเก็บเซสชัน ช่องทาง Discord, Slack, Telegram หรือช่องทางอื่นที่เงียบอยู่สามารถเชื่อมต่อใหม่ได้สำเร็จโดยไม่สร้างแถวเซสชันใหม่จนกว่าจะมีการประมวลผลข้อความ ใช้ `openclaw channels status --probe`, `openclaw status --deep` หรือ `openclaw health --verbose` เมื่อคุณต้องการตรวจสอบการเชื่อมต่อช่องทางแบบสด +รายการเซสชันไม่ใช่การตรวจสอบความพร้อมใช้งานของช่องทาง/ผู้ให้บริการ รายการเหล่านี้แสดงแถวการสนทนาที่คงอยู่จาก session stores ช่องทาง Discord, Slack, Telegram หรือช่องทางอื่นที่เงียบอยู่สามารถเชื่อมต่อใหม่ได้สำเร็จโดยไม่สร้างแถวเซสชันใหม่จนกว่าจะมีการประมวลผลข้อความ ใช้ `openclaw channels status --probe`, `openclaw status --deep` หรือ `openclaw health --verbose` เมื่อต้องการการเชื่อมต่อช่องทางแบบสด + +การตอบกลับ `sessions.list` ของ Gateway ถูกจำกัดขอบเขตโดยค่าเริ่มต้น เพื่อให้ store ขนาดใหญ่ที่ใช้งานยาวนานไม่ผูกขาด event loop ของ Gateway ส่ง `limit` ที่เป็นค่าบวกอย่างชัดเจนจาก RPC clients เมื่อต้องการกรอบผลลัพธ์ที่ต่างออกไป การตอบกลับจะมี `totalCount`, `limitApplied` และ `hasMore` เมื่อผู้เรียกต้องแสดงว่ายังมีแถวเพิ่มเติมอยู่ ```bash openclaw sessions @@ -29,22 +31,22 @@ openclaw sessions --json การเลือกขอบเขต: -- ค่าเริ่มต้น: ที่จัดเก็บเอเจนต์ค่าเริ่มต้นที่กำหนดค่าไว้ -- `--verbose`: การบันทึกรายละเอียด -- `--agent `: ที่จัดเก็บเอเจนต์ที่กำหนดค่าไว้หนึ่งรายการ -- `--all-agents`: รวมที่จัดเก็บเอเจนต์ที่กำหนดค่าไว้ทั้งหมด -- `--store `: เส้นทางที่จัดเก็บแบบระบุชัดเจน (ไม่สามารถใช้ร่วมกับ `--agent` หรือ `--all-agents` ได้) +- ค่าเริ่มต้น: store ของ agent เริ่มต้นที่กำหนดค่าไว้ +- `--verbose`: การบันทึก log แบบละเอียด +- `--agent `: store ของ agent ที่กำหนดค่าไว้หนึ่งรายการ +- `--all-agents`: รวม store ของ agent ที่กำหนดค่าไว้ทั้งหมด +- `--store `: เส้นทาง store ที่ระบุอย่างชัดเจน (ใช้ร่วมกับ `--agent` หรือ `--all-agents` ไม่ได้) -ส่งออกชุด trajectory สำหรับเซสชันที่จัดเก็บไว้: +ส่งออก trajectory bundle สำหรับเซสชันที่จัดเก็บไว้: ```bash openclaw sessions export-trajectory --session-key "agent:main:telegram:direct:123" --workspace . openclaw sessions export-trajectory --session-key "agent:main:telegram:direct:123" --output bug-123 --json ``` -นี่คือเส้นทางคำสั่งที่คำสั่ง slash `/export-trajectory` ใช้หลังจากเจ้าของอนุมัติคำขอ exec แล้ว ไดเรกทอรีเอาต์พุตจะถูกแก้เส้นทางภายใน `.openclaw/trajectory-exports/` ภายใต้เวิร์กสเปซที่เลือกเสมอ +นี่คือเส้นทางคำสั่งที่คำสั่ง slash `/export-trajectory` ใช้หลังจาก owner อนุมัติคำขอ exec แล้ว ไดเรกทอรีเอาต์พุตจะถูก resolve ภายใน `.openclaw/trajectory-exports/` ใต้ workspace ที่เลือกเสมอ -`openclaw sessions --all-agents` อ่านที่จัดเก็บเอเจนต์ที่กำหนดค่าไว้ การค้นหาเซสชันของ Gateway และ ACP มีขอบเขตกว้างกว่า: ยังรวมถึงที่จัดเก็บที่มีอยู่เฉพาะบนดิสก์ซึ่งพบภายใต้ราก `agents/` ค่าเริ่มต้น หรือราก `session.store` แบบเทมเพลต ที่จัดเก็บที่ค้นพบเหล่านั้นต้องแก้เส้นทางเป็นไฟล์ `sessions.json` ปกติภายในรากของเอเจนต์; symlink และเส้นทางที่อยู่นอกรากจะถูกข้าม +`openclaw sessions --all-agents` อ่าน store ของ agent ที่กำหนดค่าไว้ การค้นหาเซสชันของ Gateway และ ACP กว้างกว่า: ยังรวม store ที่มีเฉพาะบนดิสก์ซึ่งพบใต้ root เริ่มต้น `agents/` หรือ root `session.store` ที่ใช้ template ได้ด้วย store ที่ค้นพบเหล่านั้นต้อง resolve เป็นไฟล์ `sessions.json` ปกติภายใน root ของ agent; symlink และเส้นทางนอก root จะถูกข้าม ตัวอย่าง JSON: @@ -69,7 +71,7 @@ openclaw sessions export-trajectory --session-key "agent:main:telegram:direct:12 ## การบำรุงรักษาเพื่อล้างข้อมูล -เรียกใช้การบำรุงรักษาตอนนี้ (แทนการรอรอบการเขียนถัดไป): +เรียกใช้การบำรุงรักษาทันที (แทนที่จะรอรอบการเขียนถัดไป): ```bash openclaw sessions cleanup --dry-run @@ -80,21 +82,21 @@ openclaw sessions cleanup --enforce --active-key "agent:main:telegram:direct:123 openclaw sessions cleanup --json ``` -`openclaw sessions cleanup` ใช้การตั้งค่า `session.maintenance` จากการกำหนดค่า: +`openclaw sessions cleanup` ใช้การตั้งค่า `session.maintenance` จาก config: -- หมายเหตุเรื่องขอบเขต: `openclaw sessions cleanup` ดูแลที่จัดเก็บเซสชัน transcript และ sidecar ของ trajectory โดยไม่ตัดทอนบันทึกการรัน Cron (`cron/runs/.jsonl`) ซึ่งจัดการโดย `cron.runLog.maxBytes` และ `cron.runLog.keepLines` ใน [การกำหนดค่า Cron](/th/automation/cron-jobs#configuration) และอธิบายใน [การบำรุงรักษา Cron](/th/automation/cron-jobs#maintenance) +- หมายเหตุเกี่ยวกับขอบเขต: `openclaw sessions cleanup` บำรุงรักษา session stores, transcripts และ trajectory sidecars คำสั่งนี้ไม่ตัดแต่ง cron run logs (`cron/runs/.jsonl`) ซึ่งจัดการโดย `cron.runLog.maxBytes` และ `cron.runLog.keepLines` ใน [การกำหนดค่า Cron](/th/automation/cron-jobs#configuration) และอธิบายไว้ใน [การบำรุงรักษา Cron](/th/automation/cron-jobs#maintenance) -- `--dry-run`: ดูตัวอย่างจำนวนรายการที่จะถูกตัดทอน/จำกัดจำนวนโดยไม่เขียนข้อมูล - - ในโหมดข้อความ dry-run จะพิมพ์ตารางการดำเนินการรายเซสชัน (`Action`, `Key`, `Age`, `Model`, `Flags`) เพื่อให้คุณเห็นว่าอะไรจะถูกเก็บไว้เทียบกับลบออก -- `--enforce`: ใช้การบำรุงรักษาแม้เมื่อ `session.maintenance.mode` เป็น `warn` -- `--fix-missing`: ลบรายการที่ไม่มีไฟล์ transcript แม้ว่าปกติรายการเหล่านั้นจะยังไม่ถูกคัดออกตามอายุ/จำนวนก็ตาม -- `--active-key `: ป้องกันคีย์ที่ใช้งานอยู่รายการใดรายการหนึ่งจากการถูกขับออกเพราะงบดิสก์ ตัวชี้การสนทนาภายนอกแบบคงทน เช่น เซสชันกลุ่มและเซสชันแชตที่ผูกกับเธรด จะถูกเก็บไว้โดยการบำรุงรักษาตามอายุ/จำนวน/งบดิสก์เช่นกัน -- `--agent `: เรียกใช้การล้างข้อมูลสำหรับที่จัดเก็บเอเจนต์ที่กำหนดค่าไว้หนึ่งรายการ -- `--all-agents`: เรียกใช้การล้างข้อมูลสำหรับที่จัดเก็บเอเจนต์ที่กำหนดค่าไว้ทั้งหมด +- `--dry-run`: แสดงตัวอย่างจำนวนรายการที่จะถูกตัดแต่ง/จำกัดโดยไม่เขียนข้อมูล + - ในโหมดข้อความ dry-run จะพิมพ์ตารางการดำเนินการต่อเซสชัน (`Action`, `Key`, `Age`, `Model`, `Flags`) เพื่อให้คุณเห็นว่าสิ่งใดจะถูกเก็บไว้เทียบกับถูกลบออก +- `--enforce`: ใช้การบำรุงรักษาแม้ว่า `session.maintenance.mode` จะเป็น `warn` +- `--fix-missing`: ลบรายการที่ไม่มีไฟล์ transcript แม้ว่าปกติแล้วรายการเหล่านั้นจะยังไม่หมดอายุตามอายุ/จำนวนก็ตาม +- `--active-key `: ป้องกัน active key ที่ระบุจากการถูกขับออกเพราะงบดิสก์ ตัวชี้การสนทนาภายนอกแบบถาวร เช่น เซสชันกลุ่มและเซสชันแชทที่ผูกกับ thread จะถูกเก็บไว้โดยการบำรุงรักษาตามอายุ/จำนวน/งบดิสก์เช่นกัน +- `--agent `: เรียกใช้การล้างข้อมูลสำหรับ store ของ agent ที่กำหนดค่าไว้หนึ่งรายการ +- `--all-agents`: เรียกใช้การล้างข้อมูลสำหรับ store ของ agent ที่กำหนดค่าไว้ทั้งหมด - `--store `: เรียกใช้กับไฟล์ `sessions.json` ที่ระบุ -- `--json`: พิมพ์สรุป JSON เมื่อใช้ร่วมกับ `--all-agents` เอาต์พุตจะรวมสรุปหนึ่งรายการต่อที่จัดเก็บ +- `--json`: พิมพ์สรุป JSON เมื่อใช้ร่วมกับ `--all-agents` เอาต์พุตจะรวมสรุปหนึ่งรายการต่อ store -เมื่อ Gateway เข้าถึงได้ การล้างข้อมูลแบบไม่ใช่ dry-run สำหรับที่จัดเก็บเอเจนต์ที่กำหนดค่าไว้จะถูกส่งผ่าน Gateway เพื่อให้ใช้ตัวเขียนที่จัดเก็บเซสชันเดียวกับทราฟฟิกรันไทม์ ใช้ `--store ` สำหรับการซ่อมแซมไฟล์ที่จัดเก็บแบบออฟไลน์อย่างชัดเจน +เมื่อ Gateway เข้าถึงได้ การล้างข้อมูลแบบไม่ใช่ dry-run สำหรับ store ของ agent ที่กำหนดค่าไว้จะถูกส่งผ่าน Gateway เพื่อให้ใช้ตัวเขียน session-store เดียวกับ traffic ขณะ runtime ใช้ `--store ` สำหรับการซ่อมแซมไฟล์ store แบบ offline ที่ระบุอย่างชัดเจน `openclaw sessions cleanup --all-agents --dry-run --json`: diff --git a/docs/th/concepts/mantis.md b/docs/th/concepts/mantis.md index c66f4133a..111cbe663 100644 --- a/docs/th/concepts/mantis.md +++ b/docs/th/concepts/mantis.md @@ -1,65 +1,65 @@ --- read_when: - - การสร้างหรือเรียกใช้การตรวจสอบคุณภาพด้านภาพแบบสดสำหรับข้อบกพร่องของ OpenClaw + - การสร้างหรือเรียกใช้การตรวจสอบคุณภาพเชิงภาพแบบสดสำหรับข้อบกพร่องของ OpenClaw - การเพิ่มการตรวจสอบก่อนและหลังสำหรับคำขอดึง - การเพิ่มสถานการณ์การรับส่งแบบสดสำหรับ Discord, Slack, WhatsApp หรืออื่นๆ - การดีบักการรัน QA ที่ต้องใช้ภาพหน้าจอ การทำงานอัตโนมัติของเบราว์เซอร์ หรือการเข้าถึง VNC -summary: Mantis คือระบบตรวจสอบด้วยภาพแบบต้นทางถึงปลายทางสำหรับจำลองบั๊กของ OpenClaw ซ้ำบนทรานสปอร์ตที่ใช้งานจริง บันทึกหลักฐานก่อนและหลัง และแนบอาร์ติแฟกต์ไปยัง PR +summary: Mantis คือระบบตรวจสอบแบบต้นทางถึงปลายทางเชิงภาพสำหรับจำลองบั๊กของ OpenClaw บนทรานสปอร์ตที่ใช้งานจริง เก็บหลักฐานก่อนและหลัง และแนบอาร์ติแฟกต์กับ PR title: ตั๊กแตนตำข้าว x-i18n: - generated_at: "2026-05-04T02:23:26Z" + generated_at: "2026-05-04T07:03:23Z" model: gpt-5.5 provider: openai - source_hash: 5a86ab4bc876d1c53ada1c30580034165f028194a072f559eb54a898a369211d + source_hash: 9d3f3fa3db111b1b5c85f8efeccd749fbd5885cee6b7843ca4c8d049acfd9164 source_path: concepts/mantis.md workflow: 16 --- -Mantis คือระบบตรวจสอบแบบต้นทางถึงปลายทางของ OpenClaw สำหรับบั๊กที่ต้องใช้แรนไทม์จริง ทรานสปอร์ตจริง และหลักฐานที่มองเห็นได้ ระบบจะรันสถานการณ์กับ ref ที่ทราบว่ามีปัญหา เก็บหลักฐาน รันสถานการณ์เดียวกันกับ ref candidate แล้วเผยแพร่การเปรียบเทียบเป็นอาร์ติแฟกต์ที่ผู้ดูแลสามารถตรวจสอบได้จาก PR หรือจากคำสั่งภายในเครื่อง +Mantis คือระบบตรวจสอบแบบ end-to-end ของ OpenClaw สำหรับบั๊กที่ต้องใช้ runtime จริง, transport จริง และหลักฐานที่มองเห็นได้ ระบบจะรัน scenario กับ ref ที่ทราบว่าเสีย, จับหลักฐาน, รัน scenario เดียวกันกับ ref ผู้สมัคร, แล้วเผยแพร่การเปรียบเทียบเป็นอาร์ติแฟกต์ที่ maintainer สามารถตรวจสอบได้จาก PR หรือจากคำสั่งภายในเครื่อง -Mantis เริ่มจาก Discord เพราะ Discord ให้เลนแรกที่มีคุณค่าสูงแก่เรา: การยืนยันตัวตนบอตจริง ช่องกิลด์จริง รีแอ็กชัน เธรด คำสั่งเนทีฟ และ UI บนเบราว์เซอร์ที่มนุษย์สามารถยืนยันด้วยสายตาได้ว่าทรานสปอร์ตแสดงอะไร +Mantis เริ่มจาก Discord เพราะ Discord ให้ lane แรกที่มีคุณค่าสูงแก่เรา: การยืนยันตัวตนบอทจริง, ช่อง guild จริง, reaction, thread, คำสั่ง native และ UI บนเบราว์เซอร์ที่มนุษย์สามารถยืนยันด้วยสายตาได้ว่า transport แสดงอะไร ## เป้าหมาย -- ทำซ้ำบั๊กจาก issue หรือ PR บน GitHub ด้วยรูปแบบทรานสปอร์ตเดียวกับที่ผู้ใช้เห็น -- เก็บอาร์ติแฟกต์ **ก่อน** บน ref พื้นฐานก่อนใช้การแก้ไข -- เก็บอาร์ติแฟกต์ **หลัง** บน ref candidate หลังใช้การแก้ไข -- ใช้ oracle แบบกำหนดแน่นอนเมื่อทำได้ เช่น การอ่านรีแอ็กชันผ่าน Discord REST หรือการตรวจทรานสคริปต์ของช่อง -- เก็บภาพหน้าจอเมื่อบั๊กมีพื้นผิว UI ที่มองเห็นได้ +- จำลองบั๊กจาก GitHub issue หรือ PR ด้วยรูปแบบ transport เดียวกับที่ผู้ใช้เห็น +- จับอาร์ติแฟกต์ **before** บน ref baseline ก่อนนำ fix มาใช้ +- จับอาร์ติแฟกต์ **after** บน ref ผู้สมัครหลังนำ fix มาใช้ +- ใช้ oracle แบบ deterministic เมื่อเป็นไปได้ เช่น การอ่าน reaction ผ่าน Discord REST หรือการตรวจสอบ transcript ของช่อง +- จับภาพหน้าจอเมื่อบั๊กมีพื้นผิว UI ที่มองเห็นได้ - รันภายในเครื่องจาก CLI ที่ agent ควบคุม และรันระยะไกลจาก GitHub -- เก็บสถานะเครื่องให้เพียงพอสำหรับการกู้ผ่าน VNC เมื่อการเข้าสู่ระบบ ระบบอัตโนมัติของเบราว์เซอร์ หรือการยืนยันตัวตนของผู้ให้บริการติดขัด -- โพสต์สถานะอย่างกระชับไปยังช่อง Discord ของโอเปอเรเตอร์เมื่อการรันถูกบล็อก ต้องการความช่วยเหลือผ่าน VNC แบบแมนนวล หรือเสร็จสิ้น +- เก็บสถานะของเครื่องให้เพียงพอสำหรับการกู้ผ่าน VNC เมื่อการเข้าสู่ระบบ, การทำ browser automation หรือการยืนยันตัวตน provider ค้าง +- โพสต์สถานะอย่างกระชับไปยังช่อง Discord สำหรับ operator เมื่อการรันถูกบล็อก, ต้องการความช่วยเหลือผ่าน VNC แบบแมนนวล หรือเสร็จสิ้น ## สิ่งที่ไม่ใช่เป้าหมาย -- Mantis ไม่ใช่สิ่งทดแทน unit test โดยปกติการรัน Mantis ควรถูกแปลงเป็น regression test ที่เล็กลงหลังจากเข้าใจการแก้ไขแล้ว -- Mantis ไม่ใช่ gate CI ที่รวดเร็วตามปกติ ระบบนี้ช้ากว่า ใช้ข้อมูลประจำตัวจริง และสงวนไว้สำหรับบั๊กที่สภาพแวดล้อมจริงมีความสำคัญ -- Mantis ไม่ควรต้องพึ่งมนุษย์ในการทำงานตามปกติ VNC แบบแมนนวลเป็นเส้นทางกู้คืน ไม่ใช่เส้นทางปกติ -- Mantis ไม่เก็บความลับดิบไว้ในอาร์ติแฟกต์ ล็อก ภาพหน้าจอ รายงาน Markdown หรือคอมเมนต์ PR +- Mantis ไม่ใช่สิ่งทดแทน unit tests โดยปกติการรัน Mantis ควรถูกเปลี่ยนเป็น regression test ที่เล็กลงหลังจากเข้าใจ fix แล้ว +- Mantis ไม่ใช่ gate CI ที่เร็วตามปกติ มันช้ากว่า, ใช้ credentials จริง และสงวนไว้สำหรับบั๊กที่สภาพแวดล้อมจริงมีความสำคัญ +- Mantis ไม่ควรต้องใช้มนุษย์สำหรับการทำงานปกติ VNC แบบแมนนวลเป็นเส้นทางกู้สถานการณ์ ไม่ใช่ happy path +- Mantis ไม่เก็บ secrets ดิบในอาร์ติแฟกต์, logs, screenshots, รายงาน Markdown หรือความคิดเห็นใน PR ## ความเป็นเจ้าของ Mantis อยู่ในสแต็ก QA ของ OpenClaw -- OpenClaw เป็นเจ้าของแรนไทม์สถานการณ์ อะแดปเตอร์ทรานสปอร์ต สคีมาหลักฐาน และ CLI ภายในเครื่องภายใต้ `pnpm openclaw qa mantis` -- QA Lab เป็นเจ้าของชิ้นส่วนฮาร์เนสของทรานสปอร์ตจริง ตัวช่วยเก็บภาพเบราว์เซอร์ และตัวเขียนอาร์ติแฟกต์ -- Crabbox เป็นเจ้าของเครื่อง Linux ที่วอร์มไว้เมื่อจำเป็นต้องใช้ VM ระยะไกล -- GitHub Actions เป็นเจ้าของจุดเข้าของเวิร์กโฟลว์ระยะไกลและการเก็บรักษาอาร์ติแฟกต์ -- ClawSweeper เป็นเจ้าของการกำหนดเส้นทางคอมเมนต์ GitHub: การแยกคำสั่งผู้ดูแล การ dispatch เวิร์กโฟลว์ และการโพสต์คอมเมนต์ PR สุดท้าย -- agent ของ OpenClaw ขับเคลื่อน Mantis ผ่าน Codex เมื่อสถานการณ์ต้องการการตั้งค่าแบบ agentic การดีบัก หรือการรายงานสถานะค้าง +- OpenClaw เป็นเจ้าของ scenario runtime, transport adapters, evidence schema และ CLI ภายในเครื่องภายใต้ `pnpm openclaw qa mantis` +- QA Lab เป็นเจ้าของชิ้นส่วน live transport harness, ตัวช่วยจับภาพเบราว์เซอร์ และ artifact writers +- Crabbox เป็นเจ้าของเครื่อง Linux ที่อุ่นไว้แล้วเมื่อจำเป็นต้องใช้ VM ระยะไกล +- GitHub Actions เป็นเจ้าของ remote workflow entrypoint และการเก็บรักษาอาร์ติแฟกต์ +- ClawSweeper เป็นเจ้าของการ routing ความคิดเห็น GitHub: การ parse คำสั่ง maintainer, การ dispatch workflow และการโพสต์ความคิดเห็น PR สุดท้าย +- OpenClaw agents ขับเคลื่อน Mantis ผ่าน Codex เมื่อ scenario ต้องมีการตั้งค่าแบบ agentic, การดีบัก หรือการรายงานสถานะค้าง -ขอบเขตนี้ทำให้ความรู้ด้านทรานสปอร์ตอยู่ใน OpenClaw การจัดกำหนดการเครื่องอยู่ใน Crabbox และกาวเชื่อมเวิร์กโฟลว์ผู้ดูแลอยู่ใน ClawSweeper +ขอบเขตนี้ทำให้ความรู้เรื่อง transport อยู่ใน OpenClaw, การจัดตารางเครื่องอยู่ใน Crabbox และส่วนเชื่อม workflow ของ maintainer อยู่ใน ClawSweeper ## รูปแบบคำสั่ง -คำสั่งภายในเครื่องแรกตรวจสอบบอต Discord, กิลด์, ช่อง, การส่งข้อความ, การส่งรีแอ็กชัน และพาธอาร์ติแฟกต์: +คำสั่งภายในเครื่องคำสั่งแรกตรวจสอบบอท Discord, guild, ช่อง, การส่งข้อความ, การส่ง reaction และ path ของอาร์ติแฟกต์: ```bash pnpm openclaw qa mantis discord-smoke \ --output-dir .artifacts/qa-e2e/mantis/discord-smoke ``` -ตัวรันก่อนและหลังภายในเครื่องรับรูปแบบนี้: +runner before และ after ภายในเครื่องรับรูปแบบนี้: ```bash pnpm openclaw qa mantis run \ @@ -70,7 +70,7 @@ pnpm openclaw qa mantis run \ --output-dir .artifacts/qa-e2e/mantis/local-discord-status-reactions ``` -ตัวรันสร้าง worktree แบบ detached สำหรับ baseline และ candidate ภายใต้ไดเรกทอรีเอาต์พุต ติดตั้ง dependency บิลด์แต่ละ ref รันสถานการณ์ด้วย `--allow-failures` จากนั้นเขียน `baseline/`, `candidate/`, `comparison.json` และ `mantis-report.md` สำหรับสถานการณ์ Discord แรก การตรวจสอบที่สำเร็จหมายความว่าสถานะ baseline คือ `fail` และสถานะ candidate คือ `pass` +runner สร้าง worktree ของ baseline และ candidate แบบ detached ภายใต้ไดเรกทอรี output, ติดตั้ง dependencies, build แต่ละ ref, รัน scenario ด้วย `--allow-failures` แล้วเขียน `baseline/`, `candidate/`, `comparison.json` และ `mantis-report.md` สำหรับ scenario Discord แรก การตรวจสอบที่สำเร็จหมายความว่าสถานะ baseline คือ `fail` และสถานะ candidate คือ `pass` primitive แรกของ VM/เบราว์เซอร์คือ desktop smoke: @@ -79,30 +79,62 @@ pnpm openclaw qa mantis desktop-browser-smoke \ --output-dir .artifacts/qa-e2e/mantis/desktop-browser ``` -คำสั่งนี้เช่าหรือนำเครื่องเดสก์ท็อป Crabbox มาใช้ซ้ำ เริ่มเบราว์เซอร์ที่มองเห็นได้ภายในเซสชัน VNC เก็บภาพเดสก์ท็อป ดึงอาร์ติแฟกต์กลับมายังไดเรกทอรีเอาต์พุตภายในเครื่อง และเขียนคำสั่งเชื่อมต่อใหม่ลงในรายงาน คำสั่งตั้งค่าเริ่มต้นเป็นผู้ให้บริการ Hetzner เพราะเป็นผู้ให้บริการรายแรกที่มี desktop/VNC coverage ที่ทำงานได้ในเลน Mantis แทนที่ได้ด้วย `--provider`, `--crabbox-bin` หรือ `OPENCLAW_MANTIS_CRABBOX_PROVIDER` เมื่อรันกับฟลีต Crabbox อื่น +คำสั่งนี้เช่าหรือใช้เครื่องเดสก์ท็อป Crabbox ซ้ำ, เริ่มเบราว์เซอร์ที่มองเห็นได้ภายใน session VNC, จับภาพเดสก์ท็อป, ดึงอาร์ติแฟกต์กลับมายังไดเรกทอรี output ภายในเครื่อง และเขียนคำสั่ง reconnect ลงในรายงาน คำสั่งตั้งค่าเริ่มต้นเป็น provider Hetzner เพราะเป็น provider แรกที่มี coverage เดสก์ท็อป/VNC ใช้งานได้ใน lane ของ Mantis override ได้ด้วย `--provider`, `--crabbox-bin` หรือ `OPENCLAW_MANTIS_CRABBOX_PROVIDER` เมื่อรันกับ fleet Crabbox อื่น -แฟล็ก desktop smoke ที่มีประโยชน์: +flags ที่มีประโยชน์สำหรับ desktop smoke: -- `--lease-id ` หรือ `OPENCLAW_MANTIS_CRABBOX_LEASE_ID` นำเดสก์ท็อปที่วอร์มไว้มาใช้ซ้ำ +- `--lease-id ` หรือ `OPENCLAW_MANTIS_CRABBOX_LEASE_ID` ใช้เดสก์ท็อปที่อุ่นไว้แล้วซ้ำ - `--browser-url ` เปลี่ยนหน้าที่เปิดในเบราว์เซอร์ที่มองเห็นได้ -- `--html-file ` เรนเดอร์อาร์ติแฟกต์ HTML ภายใน repo ในเบราว์เซอร์ที่มองเห็นได้ Mantis ใช้สิ่งนี้เพื่อเก็บภาพไทม์ไลน์ Discord status-reaction ที่สร้างขึ้นผ่านเดสก์ท็อป Crabbox จริง -- `--keep-lease` หรือ `OPENCLAW_MANTIS_KEEP_VM=1` คง lease ที่สร้างใหม่และผ่านไว้สำหรับการตรวจสอบผ่าน VNC การรันที่ล้มเหลวจะคง lease ไว้ตามค่าเริ่มต้นเมื่อมีการสร้าง lease เพื่อให้โอเปอเรเตอร์เชื่อมต่อใหม่ได้ +- `--html-file ` render อาร์ติแฟกต์ HTML ภายใน repo ในเบราว์เซอร์ที่มองเห็นได้ Mantis ใช้สิ่งนี้เพื่อจับ timeline reaction สถานะ Discord ที่สร้างขึ้นผ่านเดสก์ท็อป Crabbox จริง +- `--keep-lease` หรือ `OPENCLAW_MANTIS_KEEP_VM=1` คง lease ที่สร้างใหม่และผ่านไว้เปิดอยู่สำหรับการตรวจสอบผ่าน VNC การรันที่ล้มเหลวจะคง lease ไว้โดยค่าเริ่มต้นเมื่อมีการสร้าง lease เพื่อให้ operator reconnect ได้ - `--class`, `--idle-timeout` และ `--ttl` ปรับขนาดเครื่องและอายุของ lease -เวิร์กโฟลว์ smoke บน GitHub คือ `Mantis Discord Smoke` เวิร์กโฟลว์ก่อนและหลังบน GitHub สำหรับสถานการณ์จริงแรกคือ `Mantis Discord Status Reactions` โดยรับ: +primitive transport เดสก์ท็อปแบบเต็มตัวแรกคือ Slack desktop smoke: -- `baseline_ref`: ref ที่คาดว่าจะทำซ้ำพฤติกรรม queued-only +```bash +pnpm openclaw qa mantis slack-desktop-smoke \ + --output-dir .artifacts/qa-e2e/mantis/slack-desktop \ + --gateway-setup \ + --scenario slack-canary \ + --keep-lease +``` + +คำสั่งนี้เช่าหรือใช้เครื่องเดสก์ท็อป Crabbox ซ้ำ, sync checkout ปัจจุบันเข้าไปใน VM, รัน `pnpm openclaw qa slack` ภายใน VM นั้น, เปิด Slack Web ในเบราว์เซอร์ VNC, จับภาพเดสก์ท็อปที่มองเห็นได้ และคัดลอกทั้งอาร์ติแฟกต์ Slack QA และ screenshot VNC กลับมายังไดเรกทอรี output ภายในเครื่อง นี่เป็นรูปแบบ Mantis แรกที่ทั้ง SUT OpenClaw gateway และเบราว์เซอร์อยู่ภายใน Linux desktop VM เดียวกัน + +เมื่อใช้ `--gateway-setup` คำสั่งจะเตรียม home ของ OpenClaw แบบ disposable ที่คงอยู่ที่ `$HOME/.openclaw-mantis/slack-openclaw`, patch การกำหนดค่า Slack Socket Mode สำหรับช่องที่เลือก, เริ่ม `openclaw gateway run` บน port `38973` และคง Chrome ให้รันอยู่ใน session VNC นี่คือโหมด "ปล่อยเดสก์ท็อป Linux ที่มี Slack และ claw กำลังรันไว้ให้ฉัน"; lane Slack QA แบบ bot-to-bot ยังคงเป็นค่าเริ่มต้นเมื่อไม่ได้ระบุ `--gateway-setup` + +inputs ที่จำเป็นสำหรับ `--credential-source env`: + +- `OPENCLAW_QA_SLACK_CHANNEL_ID` +- `OPENCLAW_QA_SLACK_DRIVER_BOT_TOKEN` +- `OPENCLAW_QA_SLACK_SUT_BOT_TOKEN` +- `OPENCLAW_QA_SLACK_SUT_APP_TOKEN` +- `OPENCLAW_LIVE_OPENAI_KEY` สำหรับ lane model ระยะไกล หากตั้งค่าเฉพาะ `OPENAI_API_KEY` ภายในเครื่อง Mantis จะ map ไปเป็น `OPENCLAW_LIVE_OPENAI_KEY` ก่อนเรียกใช้ Crabbox เพื่อให้การส่งต่อ env `OPENCLAW_*` ของ Crabbox พาเข้าไปใน VM ได้ + +flags Slack desktop ที่มีประโยชน์: + +- `--lease-id ` รันซ้ำกับเครื่องที่ operator ได้เข้าสู่ระบบ Slack Web ผ่าน VNC ไว้แล้ว +- `--gateway-setup` เริ่ม OpenClaw Slack gateway แบบ persistent ใน VM แทนที่จะรันเฉพาะ lane QA แบบ bot-to-bot +- `--slack-url ` เปิด Slack Web URL เฉพาะ หากไม่มี Mantis จะ derive `https://app.slack.com/client//` จาก Slack `auth.test` เมื่อมี token บอท SUT +- `--slack-channel-id ` ควบคุม allowlist ของช่อง Slack ที่ใช้โดย gateway setup +- `OPENCLAW_MANTIS_SLACK_BROWSER_PROFILE_DIR` ควบคุมโปรไฟล์ Chrome แบบ persistent ภายใน VM ค่าเริ่มต้นคือ `$HOME/.config/openclaw-mantis/slack-chrome-profile` ดังนั้นการเข้าสู่ระบบ Slack Web แบบแมนนวลจะอยู่รอดในการรันซ้ำบน lease เดียวกัน +- `--credential-source convex --credential-role ci` ใช้ shared credential pool แทน Slack env tokens โดยตรง +- `--provider-mode`, `--model`, `--alt-model` และ `--fast` ส่งผ่านไปยัง Slack live lane + +workflow smoke ของ GitHub คือ `Mantis Discord Smoke` workflow before และ after ของ GitHub สำหรับ scenario จริงแรกคือ `Mantis Discord Status Reactions` โดยรับ: + +- `baseline_ref`: ref ที่คาดว่าจะจำลองพฤติกรรม queued-only ได้ - `candidate_ref`: ref ที่คาดว่าจะแสดง `queued -> thinking -> done` -เวิร์กโฟลว์ checkout ref ของฮาร์เนสเวิร์กโฟลว์ บิลด์ worktree baseline และ candidate แยกกัน รัน `discord-status-reactions-tool-only` กับแต่ละ worktree และอัปโหลด `baseline/`, `candidate/`, `comparison.json` และ `mantis-report.md` เป็นอาร์ติแฟกต์ของ Actions นอกจากนี้ยังเรนเดอร์ HTML ไทม์ไลน์ของแต่ละเลนในเบราว์เซอร์เดสก์ท็อป Crabbox และเผยแพร่ภาพหน้าจอ VNC เหล่านั้นคู่กับ PNG ไทม์ไลน์แบบกำหนดแน่นอนในคอมเมนต์ PR เวิร์กโฟลว์บิลด์ Crabbox CLI จาก `openclaw/crabbox` main เพื่อให้ใช้แฟล็ก desktop/browser lease ปัจจุบันได้ก่อนที่จะตัด release ไบนารี Crabbox ถัดไป +มัน checkout ref ของ workflow harness, build worktree baseline และ candidate แยกกัน, รัน `discord-status-reactions-tool-only` กับแต่ละ worktree และ upload `baseline/`, `candidate/`, `comparison.json` และ `mantis-report.md` เป็นอาร์ติแฟกต์ Actions นอกจากนี้ยัง render timeline HTML ของแต่ละ lane ในเบราว์เซอร์เดสก์ท็อป Crabbox และเผยแพร่ screenshot VNC เหล่านั้นไว้ข้าง PNG timeline แบบ deterministic ในความคิดเห็น PR workflow นี้ build Crabbox CLI จาก `openclaw/crabbox` main เพื่อให้สามารถใช้ flags lease เดสก์ท็อป/เบราว์เซอร์ปัจจุบันก่อนที่จะตัด release binary Crabbox ถัดไป -คุณยังสามารถทริกเกอร์การรัน status-reactions โดยตรงจากคอมเมนต์ PR: +คุณยังสามารถ trigger การรัน status-reactions ได้โดยตรงจากความคิดเห็นใน PR: ```text @Mantis discord status reactions ``` -ทริกเกอร์คอมเมนต์นี้ตั้งใจให้แคบ โดยจะรันเฉพาะบนคอมเมนต์ pull request จากผู้ใช้ที่มีสิทธิ์ write, maintain หรือ admin และจะรู้จักเฉพาะคำขอ Discord status-reaction เท่านั้น ตามค่าเริ่มต้นจะใช้ ref พื้นฐานที่ทราบว่ามีปัญหาและ SHA ของหัว PR ปัจจุบันเป็น candidate ผู้ดูแลสามารถแทนที่ ref ใดก็ได้: +comment trigger นี้จงใจจำกัดขอบเขต มันรันเฉพาะบนความคิดเห็น pull request จากผู้ใช้ที่มีสิทธิ์ write, maintain หรือ admin และรู้จักเฉพาะคำขอ status-reaction ของ Discord โดยค่าเริ่มต้นจะใช้ ref baseline ที่ทราบว่าเสีย และ SHA head ของ PR ปัจจุบันเป็น candidate Maintainers สามารถ override ref ใดก็ได้: ```text @Mantis discord status reactions baseline=origin/main candidate=HEAD @@ -115,45 +147,45 @@ pnpm openclaw qa mantis desktop-browser-smoke \ @clawsweeper verify e2e discord ``` -คำสั่งแรกระบุชัดเจนและมุ่งเน้นสถานการณ์ คำสั่งที่สองสามารถแมป PR หรือ issue ไปยังสถานการณ์ Mantis ที่แนะนำได้ในภายหลังจากป้ายกำกับ ไฟล์ที่เปลี่ยน และข้อค้นพบจากรีวิวของ ClawSweeper +คำสั่งแรกเป็นคำสั่งแบบ explicit และเน้น scenario คำสั่งที่สองภายหลังสามารถ map PR หรือ issue ไปยัง scenario Mantis ที่แนะนำจาก labels, ไฟล์ที่เปลี่ยน และ findings จากการ review ของ ClawSweeper -## วงจรชีวิตการรัน +## วงจรการรัน -1. รับข้อมูลประจำตัว -2. จัดสรรหรือนำ VM มาใช้ซ้ำ -3. เตรียมโปรไฟล์เดสก์ท็อป/เบราว์เซอร์เมื่อสถานการณ์ต้องการหลักฐาน UI -4. เตรียม checkout ที่สะอาดสำหรับ ref พื้นฐาน -5. ติดตั้ง dependency และบิลด์เฉพาะสิ่งที่สถานการณ์ต้องใช้ -6. เริ่ม OpenClaw Gateway ลูกด้วยไดเรกทอรีสถานะแบบแยก -7. กำหนดค่าทรานสปอร์ตจริง ผู้ให้บริการ โมเดล และโปรไฟล์เบราว์เซอร์ -8. รันสถานการณ์และเก็บหลักฐาน baseline -9. หยุด gateway และเก็บรักษาล็อก +1. ดึง credentials +2. จัดสรรหรือใช้ VM ซ้ำ +3. เตรียมโปรไฟล์เดสก์ท็อป/เบราว์เซอร์เมื่อ scenario ต้องการหลักฐาน UI +4. เตรียม checkout ที่สะอาดสำหรับ ref baseline +5. ติดตั้ง dependencies และ build เฉพาะสิ่งที่ scenario ต้องใช้ +6. เริ่ม child OpenClaw Gateway ด้วยไดเรกทอรีสถานะแบบ isolated +7. กำหนดค่า live transport, provider, model และโปรไฟล์เบราว์เซอร์ +8. รัน scenario และจับหลักฐาน baseline +9. หยุด gateway และเก็บ logs ไว้ 10. เตรียม ref candidate ใน VM เดียวกัน -11. รันสถานการณ์เดียวกันและเก็บหลักฐาน candidate -12. เปรียบเทียบผลลัพธ์ oracle และหลักฐานภาพ -13. เขียน Markdown, JSON, ล็อก, ภาพหน้าจอ และอาร์ติแฟกต์ trace ที่เป็นตัวเลือก -14. อัปโหลดอาร์ติแฟกต์ GitHub Actions -15. โพสต์ข้อความสถานะ PR หรือ Discord แบบกระชับ +11. รัน scenario เดียวกันและจับหลักฐาน candidate +12. เปรียบเทียบผล oracle และหลักฐานภาพ +13. เขียน Markdown, JSON, logs, screenshots และอาร์ติแฟกต์ trace แบบ optional +14. Upload อาร์ติแฟกต์ GitHub Actions +15. โพสต์ข้อความสถานะ PR หรือ Discord อย่างกระชับ -สถานการณ์ควรล้มเหลวได้สองแบบที่แตกต่างกัน: +scenario ควรสามารถล้มเหลวได้สองแบบที่ต่างกัน: -- **ทำซ้ำบั๊กได้**: baseline ล้มเหลวในแบบที่คาดไว้ -- **ฮาร์เนสล้มเหลว**: การตั้งค่าสภาพแวดล้อม ข้อมูลประจำตัว Discord API เบราว์เซอร์ หรือผู้ให้บริการล้มเหลวก่อนที่ bug oracle จะมีความหมาย +- **จำลองบั๊กได้แล้ว**: baseline ล้มเหลวในลักษณะที่คาดไว้ +- **Harness failure**: การตั้งค่าสภาพแวดล้อม, credentials, Discord API, เบราว์เซอร์ หรือ provider ล้มเหลวก่อนที่ bug oracle จะมีความหมาย -รายงานสุดท้ายต้องแยกกรณีเหล่านี้เพื่อให้ผู้ดูแลไม่สับสนระหว่างสภาพแวดล้อมที่ไม่นิ่งกับพฤติกรรมของผลิตภัณฑ์ +รายงานสุดท้ายต้องแยกกรณีเหล่านี้ออกจากกัน เพื่อให้ maintainers ไม่สับสนระหว่างสภาพแวดล้อมที่ flaky กับพฤติกรรมของผลิตภัณฑ์ -## MVP ของ Discord +## Discord MVP -สถานการณ์แรกควรมุ่งเป้าไปที่ Discord status reactions ในช่องกิลด์ที่โหมดส่ง reply ต้นทางคือ `message_tool_only` +scenario แรกควร target status reactions ของ Discord ในช่อง guild ที่ source reply delivery mode เป็น `message_tool_only` -เหตุผลที่เป็น seed ที่ดีสำหรับ Mantis: +เหตุผลที่เป็น seed ของ Mantis ที่ดี: -- มองเห็นได้ใน Discord เป็นรีแอ็กชันบนข้อความที่ทริกเกอร์ -- มี REST oracle ที่แข็งแรงผ่านสถานะรีแอ็กชันของข้อความ Discord -- ครอบคลุม OpenClaw Gateway จริง การยืนยันตัวตนบอต Discord การ dispatch ข้อความ โหมดส่ง reply ต้นทาง สถานะรีแอ็กชัน และวงจรชีวิต turn ของโมเดล -- แคบพอที่จะทำให้การติดตั้งใช้งานครั้งแรกตรงไปตรงมา +- มองเห็นได้ใน Discord เป็น reactions บนข้อความที่ trigger +- มี REST oracle ที่แข็งแรงผ่านสถานะ reaction ของข้อความ Discord +- ทดสอบ OpenClaw Gateway จริง, การยืนยันตัวตนบอท Discord, การ dispatch ข้อความ, source reply delivery mode, สถานะ status reaction และวงจรชีวิต model turn +- แคบพอที่จะทำให้การ implement แรกซื่อตรงต่อเป้าหมาย -รูปแบบสถานการณ์ที่คาดไว้: +รูปแบบ scenario ที่คาดไว้: ```yaml id: discord-status-reactions-tool-only @@ -184,9 +216,9 @@ evidence: screenshotMessageRow: true ``` -หลักฐาน baseline ควรแสดงรีแอ็กชัน acknowledgement แบบ queued แต่ไม่มี lifecycle transition ในโหมด tool-only หลักฐาน candidate ควรแสดง lifecycle status reactions ที่ทำงานเมื่อ `messages.statusReactions.enabled` เป็น true อย่างชัดเจน +หลักฐาน baseline ควรแสดง acknowledgement reaction แบบ queued แต่ไม่มี lifecycle transition ในโหมด tool-only หลักฐาน candidate ควรแสดง lifecycle status reactions ที่ทำงานเมื่อ `messages.statusReactions.enabled` เป็น true อย่าง explicit -slice แรกที่รันได้คือสถานการณ์ QA จริงของ Discord แบบ opt-in: +slice แรกที่ executable คือ scenario Discord live QA แบบ opt-in: ```bash pnpm openclaw qa discord \ @@ -198,24 +230,34 @@ pnpm openclaw qa discord \ --output-dir .artifacts/qa-e2e/mantis/discord-status-reactions-candidate ``` -คำสั่งนี้กำหนดค่า SUT ให้จัดการกิลด์แบบเปิดตลอด, `visibleReplies: -"message_tool"`, `ackReaction: "👀"` และ status reactions ที่ระบุชัดเจน oracle จะ poll ข้อความ Discord ที่ทริกเกอร์จริงและคาดหวังลำดับที่สังเกตได้คือ `👀 -> 🤔 -> 👍` อาร์ติแฟกต์ประกอบด้วย `discord-qa-reaction-timelines.json`, `discord-status-reactions-tool-only-timeline.html` และ `discord-status-reactions-tool-only-timeline.png` +กำหนดค่า SUT ให้เปิดการจัดการกิลด์ตลอดเวลา, `visibleReplies: +"message_tool"`, `ackReaction: "👀"` และรีแอ็กชันสถานะแบบชัดเจน oracle +จะโพลข้อความกระตุ้นจริงใน Discord และคาดหวังลำดับที่สังเกตได้ +`👀 -> 🤔 -> 👍` artifact ประกอบด้วย `discord-qa-reaction-timelines.json`, +`discord-status-reactions-tool-only-timeline.html` และ +`discord-status-reactions-tool-only-timeline.png` -## ส่วนประกอบ QA ที่มีอยู่ +## ชิ้นส่วน QA ที่มีอยู่ -Mantis ควรต่อยอดจากสแต็ก QA ส่วนตัวที่มีอยู่แทนที่จะเริ่มจากศูนย์: +Mantis ควรต่อยอดจาก private QA stack ที่มีอยู่ แทนที่จะเริ่มจาก +ศูนย์: -- `pnpm openclaw qa discord` รันเลน Discord จริงพร้อมบอต driver และ SUT อยู่แล้ว -- ตัวรันทรานสปอร์ตจริงเขียนรายงานและอาร์ติแฟกต์ observed-message ภายใต้ `.artifacts/qa-e2e/` อยู่แล้ว -- lease ข้อมูลประจำตัว Convex ให้สิทธิ์เข้าถึงข้อมูลประจำตัวทรานสปอร์ตจริงที่ใช้ร่วมกันแบบเอกสิทธิ์อยู่แล้ว -- บริการควบคุมเบราว์เซอร์รองรับภาพหน้าจอ สแนปช็อต โปรไฟล์ managed แบบ headless และโปรไฟล์ CDP ระยะไกลอยู่แล้ว -- QA Lab มี UI ดีบักเกอร์และ bus สำหรับการทดสอบที่มีรูปแบบเหมือนทรานสปอร์ตอยู่แล้ว +- `pnpm openclaw qa discord` รันเลน Discord แบบ live พร้อมบอต driver และ + SUT อยู่แล้ว +- live transport runner เขียนรายงานและ artifact ของข้อความที่สังเกตได้ + ไว้ใต้ `.artifacts/qa-e2e/` อยู่แล้ว +- lease ของข้อมูลรับรอง Convex ให้สิทธิ์เข้าถึงแบบเอกสิทธิ์แก่ข้อมูลรับรอง live + transport ที่ใช้ร่วมกันอยู่แล้ว +- browser control service รองรับ screenshot, snapshot, + โปรไฟล์ managed แบบ headless และโปรไฟล์ CDP ระยะไกลอยู่แล้ว +- QA Lab มี debugger UI และ bus สำหรับการทดสอบรูปทรง transport อยู่แล้ว -การติดตั้ง Mantis ครั้งแรกสามารถเป็นตัวรันก่อน/หลังแบบบางบนชิ้นส่วนเหล่านี้ พร้อมชั้นหลักฐานภาพหนึ่งชั้น +การใช้งาน Mantis ระยะแรกสามารถเป็น runner แบบ thin ก่อน/หลังครอบชิ้นส่วนเหล่านี้ +พร้อมชั้นหลักฐานภาพหนึ่งชั้น ## โมเดลหลักฐาน -ทุกการรันเขียนไดเรกทอรีอาร์ติแฟกต์ที่เสถียร: +ทุกการรันเขียนไดเรกทอรี artifact ที่เสถียร: ```text .artifacts/qa-e2e/mantis// @@ -235,73 +277,79 @@ Mantis ควรต่อยอดจากสแต็ก QA ส่วนตั run.log ``` -`mantis-summary.json` ควรเป็นแหล่งความจริงที่เครื่องอ่านได้ รายงาน Markdown ใช้สำหรับคอมเมนต์ PR และการรีวิวโดยมนุษย์ +`mantis-summary.json` ควรเป็นแหล่งข้อมูลจริงที่เครื่องอ่านได้ +รายงาน Markdown มีไว้สำหรับคอมเมนต์ PR และการตรวจทานโดยมนุษย์ -summary ต้องมี: +สรุปต้องประกอบด้วย: - ref และ SHA ที่ทดสอบ -- ทรานสปอร์ตและรหัสสถานการณ์ -- ผู้ให้บริการเครื่องและรหัสเครื่องหรือรหัส lease -- แหล่งข้อมูลประจำตัวโดยไม่มีค่าความลับ +- transport และ scenario id +- ผู้ให้บริการเครื่องและ machine id หรือ lease id +- แหล่งข้อมูลรับรองโดยไม่มีค่าลับ - ผลลัพธ์ baseline - ผลลัพธ์ candidate -- บั๊กถูกทำซ้ำบน baseline หรือไม่ +- บั๊กเกิดซ้ำบน baseline หรือไม่ - candidate แก้ไขได้หรือไม่ -- พาธอาร์ติแฟกต์ +- path ของ artifact - ปัญหาการตั้งค่าหรือการล้างข้อมูลที่ผ่านการทำให้ปลอดภัยแล้ว -ภาพหน้าจอคือหลักฐาน ไม่ใช่ความลับ แต่ยังต้องมีวินัยด้านการ redact: ชื่อช่องส่วนตัว ชื่อผู้ใช้ หรือเนื้อหาข้อความอาจปรากฏ สำหรับ PR สาธารณะ ให้ใช้ลิงก์อาร์ติแฟกต์ GitHub Actions แทนภาพ inline จนกว่าเรื่องการ redact จะแข็งแรงขึ้น +Screenshot เป็นหลักฐาน ไม่ใช่ secret แต่ยังต้องมีวินัยในการ redaction: +ชื่อช่องส่วนตัว ชื่อผู้ใช้ หรือเนื้อหาข้อความอาจปรากฏได้ สำหรับ PR สาธารณะ +ควรใช้ลิงก์ artifact ของ GitHub Actions แทนรูปภาพแบบ inline จนกว่าเรื่อง +redaction จะแข็งแรงขึ้น ## เบราว์เซอร์และ VNC เลนเบราว์เซอร์มีสองโหมด: -- **ระบบอัตโนมัติแบบ headless**: ค่าเริ่มต้นสำหรับ CI Chrome รันโดยเปิด CDP และ Playwright หรือการควบคุมเบราว์เซอร์ของ OpenClaw จะเก็บภาพหน้าจอ -- **การกู้ผ่าน VNC**: เปิดใช้บน VM เดียวกันเมื่อการเข้าสู่ระบบ MFA ระบบป้องกันอัตโนมัติของ Discord หรือการดีบักภาพต้องใช้มนุษย์ +- **การทำงานอัตโนมัติแบบ headless**: ค่าเริ่มต้นสำหรับ CI Chrome รันโดยเปิดใช้ CDP + และ Playwright หรือ browser control ของ OpenClaw จับภาพ screenshot +- **การกู้สถานการณ์ด้วย VNC**: เปิดใช้บน VM เดียวกันเมื่อ login, MFA, + การป้องกัน automation ของ Discord หรือการ debug ด้วยภาพต้องใช้มนุษย์ -โปรไฟล์เบราว์เซอร์ผู้สังเกตการณ์ Discord ควรคงอยู่เพียงพอเพื่อหลีกเลี่ยง -การเข้าสู่ระบบทุกครั้งที่รัน แต่ต้องแยกจากสถานะเบราว์เซอร์ส่วนตัว โปรไฟล์ -เป็นของพูลเครื่อง Mantis ไม่ใช่แล็ปท็อปของนักพัฒนา +โปรไฟล์เบราว์เซอร์ผู้สังเกตการณ์ Discord ควรมี persistence พอที่จะหลีกเลี่ยง +การ login ทุกการรัน แต่แยกจากสถานะเบราว์เซอร์ส่วนตัว โปรไฟล์เป็นของพูลเครื่อง +Mantis ไม่ใช่ของแล็ปท็อปนักพัฒนา -เมื่อ Mantis ติดขัด ระบบจะโพสต์ข้อความสถานะ Discord พร้อมข้อมูลต่อไปนี้: +เมื่อ Mantis ติดขัด จะโพสต์ข้อความสถานะ Discord พร้อม: -- id การรัน -- id สถานการณ์ +- run id +- scenario id - ผู้ให้บริการเครื่อง -- ไดเรกทอรีอาร์ติแฟกต์ +- ไดเรกทอรี artifact - คำแนะนำการเชื่อมต่อ VNC หรือ noVNC หากมี -- ข้อความตัวบล็อกสั้น ๆ +- ข้อความ blocker แบบสั้น -การปรับใช้แบบส่วนตัวครั้งแรกสามารถโพสต์ข้อความเหล่านี้ไปยังช่องผู้ปฏิบัติงาน -ที่มีอยู่ แล้วค่อยย้ายไปยังช่อง Mantis เฉพาะในภายหลัง +การ deploy แบบ private ครั้งแรกสามารถโพสต์ข้อความเหล่านี้ไปยังช่อง operator +ที่มีอยู่ แล้วค่อยย้ายไปช่อง Mantis เฉพาะในภายหลัง ## เครื่อง -Mantis ควรเลือกใช้ AWS ผ่าน Crabbox สำหรับการใช้งานระยะไกลครั้งแรก -Crabbox ให้เครื่องที่อุ่นไว้แล้ว การติดตามสัญญาเช่า การเติมสภาพแวดล้อม ล็อก ผลลัพธ์ และ -การทำความสะอาด หากความจุของ AWS ช้าเกินไปหรือไม่พร้อมใช้งาน ให้เพิ่มผู้ให้บริการ Hetzner -ไว้หลังอินเทอร์เฟซเครื่องเดียวกัน +Mantis ควรเลือกใช้ AWS ผ่าน Crabbox สำหรับ remote implementation ระยะแรก +Crabbox ให้เครื่องที่อุ่นไว้แล้ว, การติดตาม lease, hydration, log, ผลลัพธ์ และ +การล้างข้อมูล หาก capacity ของ AWS ช้าเกินไปหรือไม่พร้อมใช้งาน ให้เพิ่ม provider +ของ Hetzner ไว้หลัง machine interface เดียวกัน -ข้อกำหนด VM ขั้นต่ำ: +ข้อกำหนดขั้นต่ำของ VM: -- Linux ที่มี Chrome หรือ Chromium ซึ่งรองรับเดสก์ท็อปติดตั้งอยู่ -- การเข้าถึง CDP สำหรับการทำงานอัตโนมัติของเบราว์เซอร์ -- VNC หรือ noVNC สำหรับการกู้คืน +- Linux ที่ติดตั้ง Chrome หรือ Chromium ซึ่งรองรับ desktop +- การเข้าถึง CDP สำหรับ browser automation +- VNC หรือ noVNC สำหรับการกู้สถานการณ์ - Node 22 และ pnpm -- การ checkout OpenClaw และแคช dependency -- แคชเบราว์เซอร์ Playwright Chromium เมื่อใช้ Playwright -- CPU และหน่วยความจำเพียงพอสำหรับ OpenClaw Gateway หนึ่งตัว เบราว์เซอร์หนึ่งตัว และการรันโมเดลหนึ่งครั้ง -- การเข้าถึงขาออกไปยัง Discord, GitHub, ผู้ให้บริการโมเดล และโบรกเกอร์ข้อมูลรับรอง +- checkout ของ OpenClaw และ dependency cache +- cache ของเบราว์เซอร์ Playwright Chromium เมื่อใช้ Playwright +- CPU และ memory เพียงพอสำหรับ OpenClaw Gateway หนึ่งตัว เบราว์เซอร์หนึ่งตัว และ model run หนึ่งครั้ง +- การเข้าถึงขาออกไปยัง Discord, GitHub, model provider และ credential broker -VM ไม่ควรเก็บความลับดิบที่มีอายุยาวนอกเหนือจากที่เก็บข้อมูลรับรองหรือ -ที่เก็บโปรไฟล์เบราว์เซอร์ที่คาดไว้ +VM ไม่ควรเก็บ raw secret ที่มีอายุยาวนอก credential store หรือ browser profile +store ที่คาดไว้ -## ความลับ +## Secret -ความลับอยู่ใน GitHub organization หรือ repository secrets สำหรับการรันระยะไกล และอยู่ใน -ไฟล์ความลับภายในเครื่องที่ควบคุมโดยผู้ปฏิบัติงานสำหรับการรันภายในเครื่อง +Secret อยู่ใน GitHub organization หรือ repository secrets สำหรับ remote run +และอยู่ในไฟล์ secret ที่ควบคุมโดย operator ในเครื่องสำหรับ local run -ชื่อความลับที่แนะนำ: +ชื่อ secret ที่แนะนำ: - `OPENCLAW_QA_DISCORD_MANTIS_BOT_TOKEN` - `OPENCLAW_QA_DISCORD_DRIVER_BOT_TOKEN` @@ -309,52 +357,52 @@ VM ไม่ควรเก็บความลับดิบที่มี - `OPENCLAW_QA_DISCORD_GUILD_ID` - `OPENCLAW_QA_DISCORD_CHANNEL_ID` - `OPENCLAW_QA_DISCORD_NOTIFY_CHANNEL_ID` -- `OPENCLAW_QA_REDACT_PUBLIC_METADATA=1` สำหรับการอัปโหลดอาร์ติแฟกต์ GitHub สาธารณะ +- `OPENCLAW_QA_REDACT_PUBLIC_METADATA=1` สำหรับการอัปโหลด artifact สาธารณะของ GitHub - `OPENCLAW_QA_CONVEX_SITE_URL` - `OPENCLAW_QA_CONVEX_SECRET_CI` - `OPENCLAW_QA_MANTIS_CRABBOX_COORDINATOR` - `OPENCLAW_QA_MANTIS_CRABBOX_COORDINATOR_TOKEN` -ในระยะยาว พูลข้อมูลรับรอง Convex ควรยังคงเป็นแหล่งปกติสำหรับข้อมูลรับรอง -การขนส่งแบบสด GitHub secrets ใช้บูตสแตรปโบรกเกอร์และเลนสำรอง -เวิร์กโฟลว์สถานะ-รีแอ็กชันของ Discord จับคู่ความลับ Mantis Crabbox กลับไปยัง -ตัวแปรสภาพแวดล้อม `CRABBOX_COORDINATOR` และ `CRABBOX_COORDINATOR_TOKEN` -ที่ Crabbox CLI คาดหวัง ชื่อ GitHub secret แบบธรรมดา `CRABBOX_*` ยังคง -ได้รับการยอมรับเป็น fallback เพื่อความเข้ากันได้ +ในระยะยาว credential pool ของ Convex ควรยังเป็นแหล่งปกติสำหรับข้อมูลรับรอง live +transport GitHub secrets ใช้ bootstrap broker และ fallback lane +workflow สำหรับ status reaction ของ Discord map secret ของ Mantis Crabbox กลับไปยัง +environment variable `CRABBOX_COORDINATOR` และ `CRABBOX_COORDINATOR_TOKEN` +ที่ Crabbox CLI คาดหวัง ชื่อ GitHub secret แบบ plain `CRABBOX_*` ยังรองรับเป็น +fallback เพื่อความเข้ากันได้ -ตัวรัน Mantis ต้องไม่พิมพ์สิ่งต่อไปนี้: +Mantis runner ต้องไม่พิมพ์: -- โทเค็นบอต Discord -- คีย์ API ของผู้ให้บริการ -- คุกกี้เบราว์เซอร์ -- เนื้อหาโปรไฟล์การยืนยันตัวตน +- token ของบอต Discord +- API key ของ provider +- cookie ของเบราว์เซอร์ +- เนื้อหา auth profile - รหัสผ่าน VNC -- payload ข้อมูลรับรองดิบ +- payload ข้อมูลรับรองแบบ raw -การอัปโหลดอาร์ติแฟกต์สาธารณะควรปกปิดเมทาดาทาเป้าหมาย Discord ด้วย เช่น id ของบอต, -กิลด์, ช่อง และข้อความ เวิร์กโฟลว์ smoke ของ GitHub เปิดใช้ +การอัปโหลด artifact สาธารณะควร redact metadata เป้าหมายของ Discord เช่น bot, +guild, channel และ message id ด้วย GitHub smoke workflow เปิดใช้ `OPENCLAW_QA_REDACT_PUBLIC_METADATA=1` ด้วยเหตุผลนี้ -หากโทเค็นถูกวางลงใน issue, PR, แชต หรือบันทึกโดยไม่ได้ตั้งใจ ให้หมุนเวียนโทเค็นนั้น -หลังจากเก็บความลับใหม่แล้ว +หาก token ถูกวางลงใน issue, PR, chat หรือ log โดยไม่ตั้งใจ ให้ rotate หลังจาก +จัดเก็บ secret ใหม่แล้ว -## GitHub Artifacts และความคิดเห็น PR +## GitHub Artifacts และคอมเมนต์ PR -เวิร์กโฟลว์ Mantis ควรอัปโหลดชุดหลักฐานเต็มเป็นอาร์ติแฟกต์ Actions -ที่มีอายุสั้น เมื่อเวิร์กโฟลว์ถูกรันสำหรับรายงานบั๊กหรือ PR แก้ไข ควร -เผยแพร่ภาพหน้าจอ PNG ที่ปกปิดแล้วไปยัง branch `qa-artifacts` และ upsert -ความคิดเห็นบนบั๊กหรือ PR แก้ไขนั้นพร้อมภาพหน้าจอแบบ inline ก่อน/หลัง อย่าโพสต์ -หลักฐานหลักไว้เฉพาะบน PR ระบบอัตโนมัติ QA ทั่วไป ล็อกดิบ ข้อความที่สังเกตเห็น -และหลักฐานขนาดใหญ่อื่น ๆ ให้อยู่ในอาร์ติแฟกต์ Actions +workflow ของ Mantis ควรอัปโหลด evidence bundle ทั้งหมดเป็น artifact ของ Actions +ที่มีอายุสั้น เมื่อ workflow ถูกรันสำหรับรายงานบั๊กหรือ PR แก้ไข ควร publish +screenshot PNG ที่ผ่าน redaction แล้วไปยัง branch `qa-artifacts` และ upsert +คอมเมนต์บนบั๊กหรือ PR แก้ไขนั้นพร้อม screenshot ก่อน/หลังแบบ inline อย่าโพสต์ +หลักฐานหลักไว้เฉพาะบน PR automation QA ทั่วไป raw log, ข้อความที่สังเกตได้ และ +หลักฐานขนาดใหญ่อื่น ๆ ให้อยู่ใน artifact ของ Actions -เวิร์กโฟลว์โปรดักชันควรโพสต์ความคิดเห็นเหล่านั้นด้วย Mantis GitHub App ไม่ใช่ -ด้วย `github-actions[bot]` เก็บ app id และ private key เป็น GitHub Actions +workflow production ควรโพสต์คอมเมนต์เหล่านั้นด้วย Mantis GitHub App ไม่ใช่ด้วย +`github-actions[bot]` เก็บ app id และ private key เป็น GitHub Actions secrets ชื่อ `MANTIS_GITHUB_APP_ID` และ `MANTIS_GITHUB_APP_PRIVATE_KEY` -เวิร์กโฟลว์ใช้ marker ที่ซ่อนอยู่เป็นคีย์ upsert อัปเดตความคิดเห็นนั้นเมื่อ -โทเค็นสามารถแก้ไขได้ และสร้างความคิดเห็นใหม่ที่ Mantis เป็นเจ้าของเมื่อ -marker เก่าที่บอตเป็นเจ้าของไม่สามารถแก้ไขได้ +workflow ใช้ marker ที่ซ่อนอยู่เป็น upsert key, อัปเดตคอมเมนต์นั้นเมื่อ token +แก้ไขได้ และสร้างคอมเมนต์ใหม่ที่ Mantis เป็นเจ้าของเมื่อ marker เก่าที่บอตเป็นเจ้าของ +แก้ไขไม่ได้ -ความคิดเห็น PR ควรสั้นและเน้นภาพ: +คอมเมนต์ PR ควรสั้นและมีภาพ: ```md Mantis Discord Status Reactions QA @@ -374,73 +422,70 @@ candidate showed the expected queued -> thinking -> done sequence. | | | ``` -เมื่อการรันล้มเหลวเพราะ harness ล้มเหลว ความคิดเห็นต้องระบุเช่นนั้น -แทนที่จะสื่อว่าตัวเลือก candidate ล้มเหลว +เมื่อการรันล้มเหลวเพราะ harness ล้มเหลว คอมเมนต์ต้องบอกเช่นนั้นแทนที่จะสื่อว่า +candidate ล้มเหลว -## หมายเหตุการปรับใช้แบบส่วนตัว +## หมายเหตุการ deploy แบบ private -การปรับใช้แบบส่วนตัวอาจมีแอปพลิเคชัน Discord ของ Mantis อยู่แล้ว ให้นำ -แอปพลิเคชันนั้นกลับมาใช้แทนการสร้างแอปใหม่ เมื่อแอปนั้นมีสิทธิ์บอตที่ถูกต้อง -และสามารถหมุนเวียนได้อย่างปลอดภัย +การ deploy แบบ private อาจมี application Discord ของ Mantis อยู่แล้ว ให้ใช้ +application นั้นซ้ำแทนการสร้าง app ใหม่เมื่อมี permission ของบอตที่ถูกต้องและสามารถ +rotate ได้อย่างปลอดภัย -ตั้งค่าช่องแจ้งเตือนผู้ปฏิบัติงานเริ่มต้นผ่าน secrets หรือการกำหนดค่าการปรับใช้ -ช่องนี้สามารถชี้ไปยังช่องผู้ดูแลหรือปฏิบัติการที่มีอยู่ก่อน แล้วค่อยย้ายไปยัง +ตั้งค่าช่องแจ้งเตือน operator เริ่มต้นผ่าน secret หรือ configuration ของ deployment +ช่องนี้สามารถชี้ไปที่ช่อง maintainer หรือ operations ที่มีอยู่ก่อน แล้วค่อยย้ายไปยัง ช่อง Mantis เฉพาะเมื่อมีช่องนั้นแล้ว -อย่าใส่ guild ids, channel ids, bot tokens, browser cookies หรือ VNC passwords -ในเอกสารนี้ ให้เก็บไว้ใน GitHub secrets, โบรกเกอร์ข้อมูลรับรอง หรือที่เก็บ -ความลับภายในเครื่องของผู้ปฏิบัติงาน +อย่าใส่ guild id, channel id, bot token, cookie ของเบราว์เซอร์ หรือรหัสผ่าน VNC +ไว้ในเอกสารนี้ ให้เก็บไว้ใน GitHub secrets, credential broker หรือ local secret store +ของ operator -## การเพิ่มสถานการณ์ +## การเพิ่ม scenario -สถานการณ์ Mantis ควรประกาศ: +scenario ของ Mantis ควรประกาศ: - id และชื่อเรื่อง -- การขนส่ง +- transport - ข้อมูลรับรองที่ต้องใช้ -- นโยบาย baseline ref -- นโยบาย candidate ref -- patch การกำหนดค่า OpenClaw +- นโยบาย ref ของ baseline +- นโยบาย ref ของ candidate +- patch config ของ OpenClaw - ขั้นตอนการตั้งค่า -- สิ่งกระตุ้น -- oracle baseline ที่คาดหวัง -- oracle candidate ที่คาดหวัง +- stimulus +- oracle ของ baseline ที่คาดหวัง +- oracle ของ candidate ที่คาดหวัง - เป้าหมายการจับภาพ -- งบประมาณเวลา timeout -- ขั้นตอนการทำความสะอาด +- budget timeout +- ขั้นตอนการล้างข้อมูล -สถานการณ์ควรเลือกใช้ oracle ขนาดเล็กที่มี type: +scenario ควรเลือกใช้ oracle ที่เล็กและมี type: -- สถานะรีแอ็กชัน Discord สำหรับบั๊กรีแอ็กชัน +- สถานะ reaction ของ Discord สำหรับบั๊ก reaction - การอ้างอิงข้อความ Discord สำหรับบั๊ก threading -- thread ts ของ Slack และสถานะ API รีแอ็กชันสำหรับบั๊ก Slack -- id ข้อความอีเมลและส่วนหัวสำหรับบั๊กอีเมล -- ภาพหน้าจอเบราว์เซอร์เมื่อ UI เป็นสิ่งที่สังเกตได้อย่างน่าเชื่อถือเพียงอย่างเดียว +- thread ts ของ Slack และสถานะ reaction API สำหรับบั๊ก Slack +- message id และ header ของอีเมลสำหรับบั๊กอีเมล +- screenshot ของเบราว์เซอร์เมื่อ UI เป็น observable เดียวที่เชื่อถือได้ -การตรวจด้วย vision ควรเป็นแบบเพิ่มเติม หาก API ของแพลตฟอร์มสามารถพิสูจน์บั๊กได้ ให้ใช้ -API เป็น oracle ผ่าน/ไม่ผ่าน และเก็บภาพหน้าจอไว้เพื่อเพิ่มความมั่นใจของมนุษย์ +การตรวจด้วย vision ควรเป็นแบบ additive หาก API ของแพลตฟอร์มสามารถพิสูจน์บั๊กได้ +ให้ใช้ API เป็น oracle pass/fail และเก็บ screenshot ไว้เพื่อเพิ่มความมั่นใจให้มนุษย์ -## การขยายผู้ให้บริการ +## การขยาย Provider -หลังจาก Discord ตัวรันเดียวกันสามารถเพิ่ม: +หลังจาก Discord แล้ว runner เดียวกันสามารถเพิ่ม: -- Slack: รีแอ็กชัน, thread, app mentions, modals, การอัปโหลดไฟล์ -- อีเมล: การยืนยันตัวตน Gmail และ message threading โดยใช้ `gog` เมื่อ connector - ไม่เพียงพอ -- WhatsApp: การเข้าสู่ระบบ QR, การระบุตัวตนใหม่, การส่งข้อความ, สื่อ, รีแอ็กชัน -- Telegram: group mention gating, คำสั่ง, รีแอ็กชันเมื่อพร้อมใช้งาน -- Matrix: ห้องที่เข้ารหัส, ความสัมพันธ์ของ thread หรือ reply, การ resume หลัง restart +- Slack: reaction, thread, app mention, modal, การอัปโหลดไฟล์ +- อีเมล: auth ของ Gmail และ message threading โดยใช้ `gog` เมื่อ connector ไม่เพียงพอ +- WhatsApp: การ login ด้วย QR, การระบุตัวตนซ้ำ, การส่งข้อความ, สื่อ, reaction +- Telegram: gating การ mention ในกลุ่ม, command, reaction เมื่อพร้อมใช้งาน +- Matrix: ห้องที่เข้ารหัส, ความสัมพันธ์แบบ thread หรือ reply, การ resume หลัง restart -แต่ละการขนส่งควรมีสถานการณ์ smoke ราคาถูกหนึ่งรายการ และสถานการณ์ตามกลุ่มบั๊กหนึ่งรายการขึ้นไป -สถานการณ์ภาพที่มีค่าใช้จ่ายสูงควรเป็นแบบ opt-in +แต่ละ transport ควรมี smoke scenario ราคาถูกหนึ่งรายการ และ scenario ตามชนิดบั๊ก +หนึ่งรายการขึ้นไป scenario แบบ visual ที่มีค่าใช้จ่ายสูงควรเป็น opt-in -## คำถามที่ยังเปิดอยู่ +## คำถามเปิด -- บอต Discord ใดควรเป็น driver และบอตใดควรเป็น SUT เมื่อมีการนำ - บอต Mantis ที่มีอยู่กลับมาใช้ -- การเข้าสู่ระบบเบราว์เซอร์ผู้สังเกตการณ์ควรใช้บัญชี Discord ของมนุษย์ บัญชีทดสอบ - หรือใช้เฉพาะหลักฐาน REST ที่บอตอ่านได้สำหรับเฟสแรก -- GitHub ควรเก็บอาร์ติแฟกต์ Mantis สำหรับ PR ไว้นานเท่าใด -- เมื่อใด ClawSweeper ควรแนะนำ Mantis โดยอัตโนมัติแทนการรอคำสั่ง - จากผู้ดูแล -- ภาพหน้าจอควรถูกปกปิดหรือตัดก่อนอัปโหลดสำหรับ PR สาธารณะหรือไม่ +- บอต Discord ตัวใดควรเป็น driver และตัวใดควรเป็น SUT เมื่อใช้บอต Mantis ที่มีอยู่ซ้ำ? +- การ login เบราว์เซอร์ของ observer ควรใช้บัญชี Discord ของมนุษย์, บัญชีทดสอบ + หรือใช้เฉพาะหลักฐาน REST ที่บอตอ่านได้สำหรับ phase แรก? +- GitHub ควรเก็บ artifact ของ Mantis สำหรับ PR ไว้นานเท่าใด? +- ClawSweeper ควรแนะนำ Mantis โดยอัตโนมัติเมื่อใด แทนที่จะรอ command จาก maintainer? +- ควร redact หรือ crop screenshot ก่อนอัปโหลดสำหรับ PR สาธารณะหรือไม่? diff --git a/docs/th/concepts/messages.md b/docs/th/concepts/messages.md index 11a1ee3e7..39f5c711b 100644 --- a/docs/th/concepts/messages.md +++ b/docs/th/concepts/messages.md @@ -1,22 +1,22 @@ --- read_when: - - อธิบายวิธีที่ข้อความขาเข้ากลายเป็นการตอบกลับ + - อธิบายว่าข้อความขาเข้ากลายเป็นการตอบกลับอย่างไร - การทำให้เซสชัน โหมดการจัดคิว หรือพฤติกรรมการสตรีมชัดเจนขึ้น - - การจัดทำเอกสารเรื่องการมองเห็นการให้เหตุผลและผลกระทบต่อการใช้งาน -summary: การไหลของข้อความ เซสชัน การจัดคิว และการมองเห็นการให้เหตุผล + - การจัดทำเอกสารเกี่ยวกับการมองเห็นการให้เหตุผลและผลกระทบต่อการใช้งาน +summary: โฟลว์ข้อความ เซสชัน การจัดคิว และการมองเห็นการให้เหตุผล title: ข้อความ x-i18n: - generated_at: "2026-04-30T16:27:51Z" + generated_at: "2026-05-04T07:03:43Z" model: gpt-5.5 provider: openai - source_hash: fdeee014d92767a725501691fbe0c4ee6b631acc9a2ab5cbbcf321bfee9679b9 + source_hash: 15242e21fd17a9f2013561003e108d197204d834caf51bbcdc53ffb3f118b14f source_path: concepts/messages.md workflow: 16 --- -OpenClaw จัดการข้อความขาเข้าผ่านไปป์ไลน์ของการระบุเซสชัน การจัดคิว การสตรีม การเรียกใช้เครื่องมือ และการมองเห็นการให้เหตุผล หน้านี้แสดงเส้นทางตั้งแต่ข้อความขาเข้าจนถึงข้อความตอบกลับ +OpenClaw จัดการข้อความขาเข้าผ่านไปป์ไลน์ของการระบุเซสชัน การเข้าคิว การสตรีม การเรียกใช้เครื่องมือ และการแสดงเหตุผล หน้านี้แสดงเส้นทางตั้งแต่ข้อความขาเข้าจนถึงการตอบกลับ -## ลำดับการไหลของข้อความ (ภาพรวม) +## โฟลว์ข้อความ (ระดับสูง) ``` Inbound message @@ -26,23 +26,23 @@ Inbound message -> outbound replies (channel limits + chunking) ``` -ค่าควบคุมหลักอยู่ในการกำหนดค่า: +ปุ่มปรับหลักอยู่ในการกำหนดค่า: -- `messages.*` สำหรับคำนำหน้า การจัดคิว และพฤติกรรมของกลุ่ม +- `messages.*` สำหรับคำนำหน้า การเข้าคิว และพฤติกรรมของกลุ่ม - `agents.defaults.*` สำหรับค่าเริ่มต้นของการสตรีมแบบบล็อกและการแบ่งชิ้นข้อความ -- การ override ตามช่องทาง (`channels.whatsapp.*`, `channels.telegram.*` และอื่นๆ) สำหรับขีดจำกัดและตัวเปิดปิดการสตรีม +- การแทนที่ระดับช่องทาง (`channels.whatsapp.*`, `channels.telegram.*` ฯลฯ) สำหรับเพดานจำกัดและตัวเปิดปิดการสตรีม ดูสคีมาเต็มได้ที่ [การกำหนดค่า](/th/gateway/configuration) -## การตัดข้อความขาเข้าซ้ำ +## การกรองข้อความขาเข้าซ้ำ -ช่องทางอาจส่งข้อความเดิมซ้ำหลังจากเชื่อมต่อใหม่ OpenClaw เก็บแคชอายุสั้นที่อิงตาม channel/account/peer/session/message id เพื่อให้การส่งซ้ำไม่ทริกเกอร์ agent run อีกครั้ง +ช่องทางอาจส่งข้อความเดิมซ้ำหลังจากเชื่อมต่อใหม่ OpenClaw เก็บแคชอายุสั้นที่ใช้คีย์ตามช่องทาง/บัญชี/เพียร์/เซสชัน/รหัสข้อความ เพื่อให้การส่งซ้ำไม่เรียกการรันเอเจนต์อีกครั้ง ## การหน่วงรวมข้อความขาเข้า -ข้อความที่ส่งต่อเนื่องอย่างรวดเร็วจาก **ผู้ส่งคนเดียวกัน** สามารถรวมเป็น agent turn เดียวได้ผ่าน `messages.inbound` การหน่วงรวมมีขอบเขตต่อช่องทาง + การสนทนา และใช้ข้อความล่าสุดสำหรับเธรด/ID ของการตอบกลับ +ข้อความที่ส่งติดกันอย่างรวดเร็วจาก **ผู้ส่งคนเดียวกัน** สามารถถูกรวมเป็นเทิร์นเดียวของเอเจนต์ผ่าน `messages.inbound` การหน่วงรวมมีขอบเขตต่อช่องทาง + บทสนทนา และใช้ข้อความล่าสุดสำหรับการผูกเธรด/รหัสของการตอบกลับ -การกำหนดค่า (ค่าเริ่มต้นส่วนกลาง + การ override ต่อช่องทาง): +การกำหนดค่า (ค่าเริ่มต้นระดับสากล + การแทนที่รายช่องทาง): ```json5 { @@ -61,120 +61,119 @@ Inbound message หมายเหตุ: -- การหน่วงรวมใช้กับข้อความ **แบบข้อความล้วน** เท่านั้น สื่อ/ไฟล์แนบจะถูกส่งออกทันที -- คำสั่งควบคุมจะข้ามการหน่วงรวมเพื่อให้ยังคงเป็นรายการเดี่ยว — **ยกเว้น** เมื่อช่องทางเลือกเข้าร่วมการรวม DM จากผู้ส่งคนเดียวกันอย่างชัดเจน (เช่น [BlueBubbles `coalesceSameSenderDms`](/th/channels/bluebubbles#coalescing-split-send-dms-command--url-in-one-composition)) ซึ่งคำสั่ง DM จะรออยู่ในช่วงหน่วงรวมเพื่อให้ payload แบบส่งแยกสามารถเข้าร่วม agent turn เดียวกันได้ +- การหน่วงรวมใช้กับข้อความ **ที่เป็นข้อความล้วน** เท่านั้น สื่อ/ไฟล์แนบจะถูกส่งต่อทันที +- คำสั่งควบคุมจะข้ามการหน่วงรวมเพื่อให้ยังคงเป็นข้อความเดี่ยว ยกเว้นเมื่อช่องทางเลือกใช้การรวม DM จากผู้ส่งคนเดียวกันอย่างชัดเจน (เช่น [BlueBubbles `coalesceSameSenderDms`](/th/channels/bluebubbles#coalescing-split-send-dms-command--url-in-one-composition)) ซึ่งคำสั่ง DM จะรออยู่ในหน้าต่างหน่วงรวม เพื่อให้เพย์โหลดที่ส่งแยกสามารถรวมเป็นเทิร์นเดียวกันของเอเจนต์ได้ ## เซสชันและอุปกรณ์ เซสชันเป็นของ Gateway ไม่ใช่ของไคลเอนต์ -- แชทโดยตรงจะถูกรวมเข้าเป็นคีย์เซสชันหลักของ agent +- แชทโดยตรงจะถูกรวมเข้ากับคีย์เซสชันหลักของเอเจนต์ - กลุ่ม/ช่องทางจะมีคีย์เซสชันของตัวเอง -- ที่เก็บเซสชันและบันทึกบทสนทนาอยู่บนโฮสต์ Gateway +- ที่เก็บเซสชันและทรานสคริปต์อยู่บนโฮสต์ Gateway -อุปกรณ์/ช่องทางหลายรายการสามารถแมปไปยังเซสชันเดียวกันได้ แต่ประวัติจะไม่ถูกซิงก์กลับไปยังไคลเอนต์ทุกตัวอย่างสมบูรณ์ คำแนะนำ: ใช้อุปกรณ์หลักหนึ่งเครื่องสำหรับการสนทนายาวเพื่อหลีกเลี่ยงบริบทที่แตกต่างกัน Control UI และ TUI จะแสดงบันทึกบทสนทนาของเซสชันที่อิงกับ Gateway เสมอ ดังนั้นจึงเป็นแหล่งข้อมูลจริง +อุปกรณ์/ช่องทางหลายรายการสามารถแมปไปยังเซสชันเดียวกันได้ แต่ประวัติจะไม่ถูกซิงก์กลับไปยังไคลเอนต์ทุกตัวอย่างครบถ้วน คำแนะนำ: ใช้อุปกรณ์หลักเพียงหนึ่งตัวสำหรับบทสนทนายาวเพื่อหลีกเลี่ยงบริบทที่แยกทางกัน Control UI และ TUI จะแสดงทรานสคริปต์เซสชันที่อิงจาก Gateway เสมอ ดังนั้นจึงเป็นแหล่งข้อมูลจริง รายละเอียด: [การจัดการเซสชัน](/th/concepts/session) ## เมทาดาทาของผลลัพธ์เครื่องมือ -`content` ของผลลัพธ์เครื่องมือคือผลลัพธ์ที่โมเดลมองเห็น ส่วน `details` ของผลลัพธ์เครื่องมือคือเมทาดาทารันไทม์สำหรับการเรนเดอร์ UI การวินิจฉัย การส่งสื่อ และ Plugin +`content` ของผลลัพธ์เครื่องมือคือผลลัพธ์ที่โมเดลมองเห็น ส่วน `details` ของผลลัพธ์เครื่องมือคือเมทาดาทารันไทม์สำหรับการเรนเดอร์ UI การวินิจฉัย การส่งมอบสื่อ และ Plugin -OpenClaw ทำให้ขอบเขตนั้นชัดเจน: +OpenClaw รักษาขอบเขตนั้นไว้อย่างชัดเจน: -- `toolResult.details` จะถูกตัดออกก่อน replay ของ provider และอินพุต Compaction -- บันทึกบทสนทนาเซสชันที่บันทึกไว้จะเก็บเฉพาะ `details` ที่มีขอบเขต เมทาดาทาที่ใหญ่เกินไปจะถูกแทนที่ด้วยสรุปแบบกระชับที่ทำเครื่องหมาย `persistedDetailsTruncated: true` +- `toolResult.details` จะถูกลบออกก่อนการเล่นซ้ำกับผู้ให้บริการและอินพุตของ Compaction +- ทรานสคริปต์เซสชันที่บันทึกถาวรจะเก็บเฉพาะ `details` ที่มีขนาดจำกัด เมทาดาทาที่ใหญ่เกินไปจะถูกแทนที่ด้วยสรุปแบบกระชับที่ทำเครื่องหมาย `persistedDetailsTruncated: true` - Plugin และเครื่องมือควรใส่ข้อความที่โมเดลต้องอ่านไว้ใน `content` ไม่ใช่เฉพาะใน `details` ## เนื้อหาขาเข้าและบริบทประวัติ -OpenClaw แยก **เนื้อหา prompt** ออกจาก **เนื้อหาคำสั่ง**: +OpenClaw แยก **เนื้อหาพรอมป์** ออกจาก **เนื้อหาคำสั่ง**: -- `BodyForAgent`: ข้อความหลักที่หันหน้าเข้าหาโมเดลสำหรับข้อความปัจจุบัน Plugin ของช่องทางควรทำให้ส่วนนี้โฟกัสที่ข้อความปัจจุบันของผู้ส่งซึ่งมี prompt -- `Body`: fallback ของ prompt แบบเดิม ส่วนนี้อาจรวม envelope ของช่องทางและ wrapper ประวัติแบบเลือกได้ แต่ช่องทางปัจจุบันไม่ควรพึ่งพาส่วนนี้เป็นอินพุตหลักของโมเดลเมื่อมี `BodyForAgent` -- `CommandBody`: ข้อความผู้ใช้ดิบสำหรับการแยกวิเคราะห์ directive/คำสั่ง -- `RawBody`: alias เดิมของ `CommandBody` (เก็บไว้เพื่อความเข้ากันได้) +- `BodyForAgent`: ข้อความหลักที่หันเข้าหาโมเดลสำหรับข้อความปัจจุบัน Plugin ของช่องทางควรรักษาให้ส่วนนี้เน้นเฉพาะข้อความปัจจุบันของผู้ส่งที่เป็นพรอมป์ +- `Body`: พรอมป์สำรองแบบเดิม อาจมีเอนเวโลปของช่องทางและตัวครอบประวัติเสริม แต่ช่องทางปัจจุบันไม่ควรพึ่งพาส่วนนี้เป็นอินพุตหลักของโมเดลเมื่อมี `BodyForAgent` +- `CommandBody`: ข้อความผู้ใช้ดิบสำหรับการแยกวิเคราะห์ไดเรกทีฟ/คำสั่ง +- `RawBody`: ชื่อแทนเดิมของ `CommandBody` (เก็บไว้เพื่อความเข้ากันได้) -เมื่อช่องทางส่งประวัติมา จะใช้ wrapper ร่วมกัน: +เมื่อช่องทางส่งประวัติมา จะใช้ตัวครอบร่วม: - `[Chat messages since your last reply - for context]` - `[Current message - respond to this]` -สำหรับ **แชทที่ไม่ใช่แชทโดยตรง** (กลุ่ม/ช่องทาง/ห้อง) **เนื้อหาข้อความปัจจุบัน** จะมีคำนำหน้าด้วยป้ายกำกับผู้ส่ง (สไตล์เดียวกับที่ใช้กับรายการประวัติ) สิ่งนี้ทำให้ข้อความแบบเรียลไทม์และข้อความที่อยู่ในคิว/ประวัติสอดคล้องกันใน prompt ของ agent +สำหรับ **แชทที่ไม่ใช่แชทโดยตรง** (กลุ่ม/ช่องทาง/ห้อง) **เนื้อหาข้อความปัจจุบัน** จะนำหน้าด้วยป้ายชื่อผู้ส่ง (สไตล์เดียวกับที่ใช้กับรายการประวัติ) วิธีนี้ทำให้ข้อความแบบเรียลไทม์และข้อความในคิว/ประวัติสอดคล้องกันในพรอมป์ของเอเจนต์ -บัฟเฟอร์ประวัติเป็นแบบ **รอดำเนินการเท่านั้น**: รวมข้อความกลุ่มที่ _ไม่ได้_ ทริกเกอร์ run (เช่น ข้อความที่ถูกกั้นด้วยการ mention) และ **ไม่รวม** ข้อความที่อยู่ในบันทึกบทสนทนาเซสชันแล้ว +บัฟเฟอร์ประวัติเป็นแบบ **รอดำเนินการเท่านั้น**: รวมข้อความกลุ่มที่ _ไม่ได้_ เรียกการรัน (เช่น ข้อความที่ถูกกั้นด้วยการกล่าวถึง) และ **ไม่รวม** ข้อความที่มีอยู่แล้วในทรานสคริปต์เซสชัน -การตัด directive ใช้กับส่วน **ข้อความปัจจุบัน** เท่านั้นเพื่อให้ประวัติยังคงครบถ้วน ช่องทางที่ครอบประวัติควรตั้งค่า `CommandBody` (หรือ `RawBody`) เป็นข้อความเดิม และเก็บ `Body` เป็น prompt ที่รวมแล้ว ประวัติแบบมีโครงสร้าง การตอบกลับ ข้อความที่ส่งต่อ และเมทาดาทาช่องทางจะถูกเรนเดอร์เป็นบล็อกบริบทที่ไม่น่าเชื่อถือในบทบาทผู้ใช้ระหว่างการประกอบ prompt -บัฟเฟอร์ประวัติกำหนดค่าได้ผ่าน `messages.groupChat.historyLimit` (ค่าเริ่มต้นส่วนกลาง) และการ override ต่อช่องทาง เช่น `channels.slack.historyLimit` หรือ `channels.telegram.accounts..historyLimit` (ตั้งเป็น `0` เพื่อปิดใช้) +การตัดไดเรกทีฟออกจะใช้เฉพาะกับส่วน **ข้อความปัจจุบัน** เพื่อให้ประวัติยังคงครบถ้วน ช่องทางที่ครอบประวัติควรตั้ง `CommandBody` (หรือ `RawBody`) เป็นข้อความต้นฉบับ และเก็บ `Body` เป็นพรอมป์ที่รวมแล้ว ประวัติที่มีโครงสร้าง การตอบกลับ ข้อความที่ส่งต่อ และเมทาดาทาของช่องทางจะถูกเรนเดอร์เป็นบล็อกบริบทที่ไม่น่าเชื่อถือในบทบาทผู้ใช้ระหว่างการประกอบพรอมป์ +บัฟเฟอร์ประวัติสามารถกำหนดค่าได้ผ่าน `messages.groupChat.historyLimit` (ค่าเริ่มต้นระดับสากล) และการแทนที่รายช่องทาง เช่น `channels.slack.historyLimit` หรือ `channels.telegram.accounts..historyLimit` (ตั้ง `0` เพื่อปิดใช้งาน) -## การจัดคิวและ followup +## การเข้าคิวและการติดตามผล -หากมี run ที่กำลังทำงานอยู่ ข้อความขาเข้าสามารถถูกจัดคิว นำไป steer เข้าสู่ run ปัจจุบัน หรือรวบรวมไว้สำหรับ turn followup ได้ +หากมีการรันทำงานอยู่แล้ว ข้อความขาเข้าสามารถถูกเข้าคิว ถูกนำทางเข้าไปในการรันปัจจุบัน หรือถูกรวบรวมไว้สำหรับเทิร์นติดตามผล - กำหนดค่าผ่าน `messages.queue` (และ `messages.queue.byChannel`) -- โหมดเริ่มต้นคือ `steer` พร้อมการหน่วงรวม followup 500ms เมื่อการ steer fallback ไปเป็นการส่ง followup ที่จัดคิวไว้ -- โหมด: `steer`, `followup`, `collect`, `steer-backlog`, `interrupt` และโหมดเดิมแบบทีละรายการ `queue` +- โหมดเริ่มต้นคือ `steer` พร้อมการหน่วงรวมติดตามผล 500ms เมื่อการนำทางย้อนกลับไปใช้การส่งมอบติดตามผลแบบเข้าคิว +- โหมด: `steer`, `followup`, `collect`, `steer-backlog`, `interrupt` และโหมด `queue` แบบเดิมที่ทำทีละรายการ -รายละเอียด: [คิวคำสั่ง](/th/concepts/queue) และ [คิวการ steer](/th/concepts/queue-steering) +รายละเอียด: [คิวคำสั่ง](/th/concepts/queue) และ [คิวการนำทาง](/th/concepts/queue-steering) -## ความเป็นเจ้าของ run ของช่องทาง +## ความเป็นเจ้าของการรันของช่องทาง -Plugin ของช่องทางอาจรักษาลำดับ หน่วงรวมอินพุต และใช้ backpressure ของทรานสปอร์ตก่อนที่ข้อความจะเข้าสู่คิวเซสชัน ไม่ควรกำหนด timeout แยกต่างหากรอบ agent turn เอง เมื่อข้อความถูก route ไปยังเซสชันแล้ว งานที่รันนานจะถูกควบคุมโดย lifecycle ของเซสชัน เครื่องมือ และรันไทม์ เพื่อให้ทุกช่องทางรายงานและกู้คืนจาก turn ที่ช้าได้อย่างสอดคล้องกัน +Plugin ของช่องทางอาจรักษาลำดับ หน่วงรวมอินพุต และใช้แรงดันย้อนกลับของการขนส่งก่อนที่ข้อความจะเข้าสู่คิวเซสชัน แต่ไม่ควรกำหนดเวลาหมดอายุแยกต่างหากรอบเทิร์นของเอเจนต์เอง เมื่อข้อความถูกกำหนดเส้นทางไปยังเซสชันแล้ว งานที่ใช้เวลานานจะถูกควบคุมโดยวงจรชีวิตของเซสชัน เครื่องมือ และรันไทม์ เพื่อให้ทุกช่องทางรายงานและกู้คืนจากเทิร์นที่ช้าได้อย่างสอดคล้องกัน ## การสตรีม การแบ่งชิ้นข้อความ และการจัดชุด -การสตรีมแบบบล็อกส่งข้อความตอบกลับบางส่วนเมื่อโมเดลผลิตบล็อกข้อความ -การแบ่งชิ้นข้อความเคารพขีดจำกัดข้อความของช่องทางและหลีกเลี่ยงการแยก fenced code +การสตรีมแบบบล็อกส่งการตอบกลับบางส่วนเมื่อโมเดลสร้างบล็อกข้อความ การแบ่งชิ้นข้อความเคารพขีดจำกัดข้อความของช่องทางและหลีกเลี่ยงการตัดแบ่งโค้ดแบบมีรั้ว การตั้งค่าหลัก: -- `agents.defaults.blockStreamingDefault` (`on|off`, ค่าเริ่มต้น off) +- `agents.defaults.blockStreamingDefault` (`on|off`, ค่าเริ่มต้นปิด) - `agents.defaults.blockStreamingBreak` (`text_end|message_end`) - `agents.defaults.blockStreamingChunk` (`minChars|maxChars|breakPreference`) -- `agents.defaults.blockStreamingCoalesce` (การจัดชุดตาม idle) -- `agents.defaults.humanDelay` (การหยุดแบบคล้ายมนุษย์ระหว่างข้อความตอบกลับแบบบล็อก) -- การ override ของช่องทาง: `*.blockStreaming` และ `*.blockStreamingCoalesce` (ช่องทางที่ไม่ใช่ Telegram ต้องมี `*.blockStreaming: true` อย่างชัดเจน) +- `agents.defaults.blockStreamingCoalesce` (การจัดชุดตามเวลาว่าง) +- `agents.defaults.humanDelay` (การหยุดพักคล้ายมนุษย์ระหว่างการตอบกลับแบบบล็อก) +- การแทนที่ระดับช่องทาง: `*.blockStreaming` และ `*.blockStreamingCoalesce` (ช่องทางที่ไม่ใช่ Telegram ต้องมี `*.blockStreaming: true` อย่างชัดเจน) รายละเอียด: [การสตรีม + การแบ่งชิ้นข้อความ](/th/concepts/streaming) -## การมองเห็นการให้เหตุผลและ token +## การแสดงเหตุผลและโทเคน OpenClaw สามารถเปิดเผยหรือซ่อนการให้เหตุผลของโมเดลได้: -- `/reasoning on|off|stream` ควบคุมการมองเห็น -- เนื้อหาการให้เหตุผลยังคงนับรวมในปริมาณการใช้ token เมื่อโมเดลสร้างขึ้น -- Telegram รองรับการสตรีมการให้เหตุผลเข้าไปใน bubble แบบร่าง +- `/reasoning on|off|stream` ควบคุมการแสดงผล +- เนื้อหาการให้เหตุผลยังคงนับรวมในการใช้โทเคนเมื่อโมเดลสร้างขึ้น +- Telegram รองรับการสตรีมเหตุผลไปยังบับเบิลฉบับร่างชั่วคราวที่จะถูกลบหลังส่งมอบคำตอบสุดท้าย ใช้ `/reasoning on` สำหรับเอาต์พุตเหตุผลแบบคงอยู่ -รายละเอียด: [directive สำหรับ Thinking + reasoning](/th/tools/thinking) และ [การใช้ token](/th/reference/token-use) +รายละเอียด: [ไดเรกทีฟการคิด + การให้เหตุผล](/th/tools/thinking) และ [การใช้โทเคน](/th/reference/token-use) ## คำนำหน้า เธรด และการตอบกลับ การจัดรูปแบบข้อความขาออกถูกรวมศูนย์ไว้ใน `messages`: -- `messages.responsePrefix`, `channels..responsePrefix` และ `channels..accounts..responsePrefix` (ลำดับคำนำหน้าขาออก) รวมถึง `channels.whatsapp.messagePrefix` (คำนำหน้าขาเข้าของ WhatsApp) -- การทำเธรดคำตอบผ่าน `replyToMode` และค่าเริ่มต้นต่อช่องทาง +- `messages.responsePrefix`, `channels..responsePrefix` และ `channels..accounts..responsePrefix` (ลำดับการใช้คำนำหน้าขาออก), รวมถึง `channels.whatsapp.messagePrefix` (คำนำหน้าขาเข้าของ WhatsApp) +- การผูกเธรดการตอบกลับผ่าน `replyToMode` และค่าเริ่มต้นรายช่องทาง -รายละเอียด: [การกำหนดค่า](/th/gateway/config-agents#messages) และเอกสารช่องทาง +รายละเอียด: [การกำหนดค่า](/th/gateway/config-agents#messages) และเอกสารของช่องทาง ## การตอบกลับแบบเงียบ -silent token ที่แน่นอน `NO_REPLY` / `no_reply` หมายถึง “อย่าส่งคำตอบที่ผู้ใช้มองเห็น” -เมื่อ turn มีสื่อเครื่องมือที่รอดำเนินการด้วย เช่น เสียง TTS ที่สร้างขึ้น OpenClaw จะตัดข้อความแบบเงียบออกแต่ยังคงส่งไฟล์แนบสื่อ -OpenClaw แก้พฤติกรรมนั้นตามประเภทการสนทนา: +โทเคนเงียบที่ตรงตัว `NO_REPLY` / `no_reply` หมายถึง “อย่าส่งคำตอบที่ผู้ใช้มองเห็น” +เมื่อเทิร์นหนึ่งยังมีสื่อเครื่องมือที่รอดำเนินการด้วย เช่น เสียง TTS ที่สร้างขึ้น OpenClaw จะตัดข้อความเงียบออก แต่ยังส่งมอบไฟล์แนบสื่อนั้น +OpenClaw แก้พฤติกรรมนั้นตามประเภทบทสนทนา: -- การสนทนาโดยตรงไม่อนุญาตความเงียบตามค่าเริ่มต้น และเขียนคำตอบแบบเงียบล้วนใหม่เป็น fallback สั้นๆ ที่มองเห็นได้ +- บทสนทนาโดยตรงไม่อนุญาตความเงียบตามค่าเริ่มต้น และเขียนคำตอบเงียบล้วนใหม่เป็นข้อความสำรองสั้น ๆ ที่มองเห็นได้ - กลุ่ม/ช่องทางอนุญาตความเงียบตามค่าเริ่มต้น - การประสานงานภายในอนุญาตความเงียบตามค่าเริ่มต้น -OpenClaw ยังใช้การตอบกลับแบบเงียบสำหรับความล้มเหลวของ runner ภายในที่เกิดขึ้นก่อนคำตอบของ assistant ใดๆ ในแชทที่ไม่ใช่แชทโดยตรง เพื่อให้กลุ่ม/ช่องทางไม่เห็นข้อความ error boilerplate ของ Gateway แชทโดยตรงจะแสดงข้อความความล้มเหลวแบบกระชับตามค่าเริ่มต้น รายละเอียด runner ดิบจะแสดงเฉพาะเมื่อ `/verbose` เป็น `on` หรือ `full` +OpenClaw ยังใช้การตอบกลับแบบเงียบสำหรับความล้มเหลวของรันเนอร์ภายในที่เกิดขึ้นก่อนมีการตอบกลับจากผู้ช่วยในแชทที่ไม่ใช่แชทโดยตรง เพื่อให้กลุ่ม/ช่องทางไม่เห็นข้อความข้อผิดพลาดสำเร็จรูปของ Gateway แชทโดยตรงจะแสดงข้อความความล้มเหลวแบบกระชับตามค่าเริ่มต้น รายละเอียดรันเนอร์ดิบจะแสดงเฉพาะเมื่อ `/verbose` เป็น `on` หรือ `full` -ค่าเริ่มต้นอยู่ภายใต้ `agents.defaults.silentReply` และ `agents.defaults.silentReplyRewrite`; `surfaces..silentReply` และ `surfaces..silentReplyRewrite` สามารถ override ต่อ surface ได้ +ค่าเริ่มต้นอยู่ใต้ `agents.defaults.silentReply` และ `agents.defaults.silentReplyRewrite`; `surfaces..silentReply` และ `surfaces..silentReplyRewrite` สามารถแทนที่ต่อพื้นผิวได้ -เมื่อเซสชันแม่มี spawned subagent run ที่รอดำเนินการอย่างน้อยหนึ่งรายการ การตอบกลับแบบเงียบล้วนจะถูกทิ้งในทุก surface แทนที่จะถูกเขียนใหม่ เพื่อให้เซสชันแม่ยังคงเงียบจนกว่าเหตุการณ์ child completion จะส่งคำตอบจริง +เมื่อเซสชันแม่มีการรันซับเอเจนต์ที่สร้างไว้และรอดำเนินการหนึ่งรายการขึ้นไป การตอบกลับเงียบล้วนจะถูกทิ้งบนทุกพื้นผิวแทนการเขียนใหม่ เพื่อให้เซสชันแม่ยังเงียบอยู่จนกว่าอีเวนต์เสร็จสิ้นของลูกจะส่งมอบคำตอบจริง ## ที่เกี่ยวข้อง -- [การสตรีม](/th/concepts/streaming) — การส่งข้อความแบบเรียลไทม์ -- [ลองใหม่](/th/concepts/retry) — พฤติกรรมการลองส่งข้อความใหม่ -- [คิว](/th/concepts/queue) — คิวประมวลผลข้อความ -- [ช่องทาง](/th/channels) — การเชื่อมต่อกับแพลตฟอร์มส่งข้อความ +- [การสตรีม](/th/concepts/streaming) — การส่งมอบข้อความแบบเรียลไทม์ +- [การลองใหม่](/th/concepts/retry) — พฤติกรรมการลองส่งมอบข้อความใหม่ +- [คิว](/th/concepts/queue) — คิวการประมวลผลข้อความ +- [ช่องทาง](/th/channels) — การผสานรวมแพลตฟอร์มรับส่งข้อความ diff --git a/docs/th/concepts/progress-drafts.md b/docs/th/concepts/progress-drafts.md index 3f48009eb..e1c6ccf77 100644 --- a/docs/th/concepts/progress-drafts.md +++ b/docs/th/concepts/progress-drafts.md @@ -1,26 +1,26 @@ --- read_when: - - การกำหนดค่าการอัปเดตความคืบหน้าที่มองเห็นได้สำหรับรอบการสนทนาที่ใช้เวลานาน - - การเลือกระหว่างโหมดสตรีมมิงแบบบางส่วน แบบบล็อก และแบบความคืบหน้า - - อธิบายวิธีที่ OpenClaw อัปเดตข้อความเดียวในช่องระหว่างที่งานกำลังดำเนินอยู่ - - การแก้ไขปัญหาร่างความคืบหน้า ข้อความความคืบหน้าแบบแยกอิสระ หรือกลไกสำรองสำหรับการสรุปผล -summary: 'ฉบับร่างความคืบหน้า: ข้อความงานที่กำลังดำเนินการที่มองเห็นได้หนึ่งรายการ ซึ่งอัปเดตระหว่างที่ agent ทำงาน' + - การกำหนดค่าการอัปเดตความคืบหน้าที่มองเห็นได้สำหรับรอบแชตที่ใช้เวลานาน + - การเลือกระหว่างโหมดการสตรีมแบบบางส่วน แบบบล็อก และแบบความคืบหน้า + - อธิบายว่า OpenClaw อัปเดตข้อความหนึ่งรายการในช่องทางอย่างไรขณะที่งานกำลังดำเนินอยู่ + - การแก้ไขปัญหาร่างความคืบหน้า ข้อความความคืบหน้าแบบแยกอิสระ หรือกลไกสำรองในการสรุปผล +summary: 'ร่างความคืบหน้า: ข้อความแสดงงานระหว่างดำเนินการที่มองเห็นได้หนึ่งข้อความ ซึ่งอัปเดตระหว่างที่เอเจนต์ทำงาน' title: ฉบับร่างความคืบหน้า x-i18n: - generated_at: "2026-05-04T02:23:44Z" + generated_at: "2026-05-04T07:04:15Z" model: gpt-5.5 provider: openai - source_hash: 8ce19262800f1c3c3e505a3cf1d41ed5c3dffcbca168ad7b7afabdce62eee8fe + source_hash: f78c07866cd7f613012a80a40413e5866c1dd2edd477088f9fc141347f5f3788 source_path: concepts/progress-drafts.md workflow: 16 --- -ร่างความคืบหน้าช่วยให้เทิร์นของ agent ที่ใช้เวลานานดูมีการดำเนินการอยู่ในแชต โดยไม่ทำให้ -บทสนทนากลายเป็นกองข้อความตอบกลับสถานะชั่วคราว +ร่างความคืบหน้าทำให้เทิร์นของเอเจนต์ที่ทำงานนานดูมีชีวิตในแชต โดยไม่ทำให้ +บทสนทนากลายเป็นกองข้อความสถานะชั่วคราว -เมื่อเปิดใช้ร่างความคืบหน้า OpenClaw จะสร้างข้อความงานระหว่างทำที่มองเห็นได้หนึ่งข้อความ -เฉพาะหลังจากเทิร์นนั้นพิสูจน์แล้วว่ากำลังทำงานจริง อัปเดตข้อความนั้นขณะที่ -agent อ่าน วางแผน เรียกเครื่องมือ หรือรอการอนุมัติ จากนั้นเปลี่ยนร่างนั้น +เมื่อเปิดใช้ร่างความคืบหน้า OpenClaw จะสร้างข้อความงานที่กำลังดำเนินการที่มองเห็นได้หนึ่งข้อความ +เฉพาะหลังจากที่เทิร์นพิสูจน์แล้วว่ากำลังทำงานจริง อัปเดตข้อความนั้นขณะที่ +เอเจนต์อ่าน วางแผน เรียกใช้เครื่องมือ หรือรอการอนุมัติ แล้วเปลี่ยนร่างนั้น เป็นคำตอบสุดท้ายเมื่อช่องทางสามารถทำได้อย่างปลอดภัย ```text @@ -49,58 +49,57 @@ Shelling... } ``` -โดยทั่วไปเท่านี้ก็เพียงพอแล้ว OpenClaw จะเลือกป้ายกำกับคำเดียวโดยอัตโนมัติ รอ -จนกว่างานจะใช้เวลาอย่างน้อยห้าวินาทีหรือปล่อยเหตุการณ์งานครั้งที่สอง เพิ่มบรรทัด -ความคืบหน้าแบบกระชับขณะที่มีงานที่เป็นประโยชน์เกิดขึ้น และระงับข้อความความคืบหน้า -แยกซ้ำๆ สำหรับเทิร์นนั้น +โดยปกติเพียงเท่านี้ก็พอ OpenClaw จะเลือกป้ายกำกับแบบคำเดียวโดยอัตโนมัติ รอ +จนกว่างานจะใช้เวลาอย่างน้อยห้าวินาทีหรือปล่อยเหตุการณ์งานที่สอง เพิ่มบรรทัด +ความคืบหน้าแบบกะทัดรัดขณะที่มีงานที่เป็นประโยชน์เกิดขึ้น และระงับข้อความคุย +ความคืบหน้าแบบเดี่ยวที่ซ้ำกันสำหรับเทิร์นนั้น ## สิ่งที่ผู้ใช้เห็น ร่างความคืบหน้ามีสองส่วน: -| ส่วน | วัตถุประสงค์ | +| ส่วน | วัตถุประสงค์ | | -------------- | --------------------------------------------------------------------------- | -| ป้ายกำกับ | ชื่อสั้นๆ เช่น `Thinking...` หรือ `Shelling...` | -| บรรทัดความคืบหน้า | อัปเดตการทำงานแบบกระชับโดยใช้ป้ายกำกับเครื่องมือและไอคอนเดียวกับเอาต์พุตแบบละเอียด | +| ป้ายกำกับ | ชื่อสั้นๆ เช่น `Thinking...` หรือ `Shelling...` | +| บรรทัดความคืบหน้า | การอัปเดตการทำงานแบบกะทัดรัด โดยใช้ป้ายกำกับและไอคอนเครื่องมือเดียวกับเอาต์พุตแบบละเอียด | -ป้ายกำกับจะปรากฏหลังจาก agent เริ่มงานที่มีความหมาย และยังคงทำงานอยู่ -เป็นเวลาห้าวินาทีหรือปล่อยเหตุการณ์งานครั้งที่สอง การตอบกลับที่เป็นข้อความล้วนจะไม่ -แสดงร่างความคืบหน้า บรรทัดความคืบหน้าจะถูกเพิ่มเฉพาะเมื่อ agent ปล่อย -อัปเดตงานที่เป็นประโยชน์ เช่น `🛠️ Exec`, `🔎 Web Search` หรือ `✍️ Write: to /tmp/file` -โดยค่าเริ่มต้นจะใช้โหมดอธิบายแบบกระชับเดียวกับ `/verbose`; ตั้งค่า -`agents.defaults.toolProgressDetail: "raw"` เมื่อดีบักและคุณต้องการให้ต่อท้าย -คำสั่ง/รายละเอียดดิบด้วย -คำตอบสุดท้ายจะแทนที่ร่างเมื่อทำได้ มิฉะนั้น -OpenClaw จะส่งคำตอบสุดท้ายตามปกติ และล้างหรือตัดการอัปเดต -ร่างตาม transport ของช่องทางนั้น +ป้ายกำกับจะปรากฏหลังจากเอเจนต์เริ่มงานที่มีความหมาย และยังคงยุ่งอยู่ +เป็นเวลาห้าวินาทีหรือปล่อยเหตุการณ์งานที่สอง คำตอบแบบข้อความล้วนเท่านั้นจะไม่ +แสดงร่างความคืบหน้า บรรทัดความคืบหน้าจะถูกเพิ่มเฉพาะเมื่อเอเจนต์ปล่อยการอัปเดต +งานที่เป็นประโยชน์ เช่น `🛠️ Exec`, `🔎 Web Search` หรือ `✍️ Write: to /tmp/file` +โดยค่าเริ่มต้น บรรทัดเหล่านี้ใช้โหมดอธิบายแบบกะทัดรัดเดียวกับ `/verbose`; ตั้งค่า +`agents.defaults.toolProgressDetail: "raw"` เมื่อดีบักและคุณต้องการให้ผนวกคำสั่ง/รายละเอียดดิบด้วย +คำตอบสุดท้ายจะแทนที่ร่างเมื่อเป็นไปได้ มิฉะนั้น +OpenClaw จะส่งคำตอบสุดท้ายตามปกติ และล้างหรือหยุดอัปเดตร่าง +ตามการขนส่งของช่องทางนั้น ## เลือกโหมด -`channels..streaming.mode` ควบคุมลักษณะงานระหว่างทำที่มองเห็นได้: +`channels..streaming.mode` ควบคุมพฤติกรรมงานที่กำลังดำเนินการที่มองเห็นได้: -| โหมด | เหมาะสำหรับ | สิ่งที่ปรากฏในแชต | +| โหมด | เหมาะที่สุดสำหรับ | สิ่งที่ปรากฏในแชต | | ---------- | -------------------------------- | ------------------------------------------------- | -| `off` | ช่องทางที่ต้องการความเงียบ | เฉพาะคำตอบสุดท้าย | -| `partial` | การดูข้อความคำตอบปรากฏขึ้น | ร่างหนึ่งฉบับที่แก้ไขด้วยข้อความคำตอบล่าสุด | -| `block` | ก้อนพรีวิวคำตอบที่ใหญ่ขึ้น | พรีวิวหนึ่งรายการที่อัปเดตหรือต่อท้ายเป็นก้อนใหญ่ขึ้น | -| `progress` | เทิร์นที่ใช้เครื่องมือมากหรือทำงานนาน | ร่างสถานะหนึ่งฉบับ แล้วตามด้วยคำตอบสุดท้าย | +| `off` | ช่องทางที่ต้องการความเงียบ | เฉพาะคำตอบสุดท้าย | +| `partial` | การดูข้อความคำตอบค่อยๆ ปรากฏ | ร่างหนึ่งข้อความที่แก้ไขด้วยข้อความคำตอบล่าสุด | +| `block` | ชิ้นส่วนตัวอย่างคำตอบที่ใหญ่ขึ้น | ตัวอย่างหนึ่งรายการที่อัปเดตหรือผนวกเป็นชิ้นใหญ่ขึ้น | +| `progress` | เทิร์นที่ใช้เครื่องมือมากหรือทำงานนาน | ร่างสถานะหนึ่งข้อความ แล้วตามด้วยคำตอบสุดท้าย | -เลือก `progress` เมื่อผู้ใช้ให้ความสำคัญกับ "กำลังเกิดอะไรขึ้น" มากกว่าการดู -ข้อความคำตอบสตรีมทีละ token +เลือก `progress` เมื่อผู้ใช้สนใจว่า "กำลังเกิดอะไรขึ้น" มากกว่าการดู +ข้อความคำตอบสตรีมทีละโทเคน เลือก `partial` เมื่อคำตอบเองเป็นสัญญาณความคืบหน้า -เลือก `block` เมื่อคุณต้องการอัปเดตร่างพรีวิวเป็นก้อนข้อความที่ใหญ่ขึ้น บน -Discord และ Telegram, `streaming.mode: "block"` ยังคงเป็นการสตรีมพรีวิว ไม่ใช่ -การส่งแบบบล็อกปกติ ใช้ `streaming.block.enabled` หรือ -`blockStreaming` แบบเก่าเมื่อคุณต้องการการตอบกลับแบบบล็อกปกติ +เลือก `block` เมื่อคุณต้องการการอัปเดตร่างตัวอย่างเป็นชิ้นข้อความที่ใหญ่ขึ้น บน +Discord และ Telegram, `streaming.mode: "block"` ยังเป็นการสตรีมตัวอย่าง ไม่ใช่ +การส่งแบบบล็อกปกติ ใช้ `streaming.block.enabled` หรือแบบเดิม +`blockStreaming` เมื่อคุณต้องการคำตอบแบบบล็อกปกติ ## กำหนดค่าป้ายกำกับ ป้ายกำกับความคืบหน้าอยู่ภายใต้ `channels..streaming.progress` ป้ายกำกับเริ่มต้นคือ `auto` ซึ่งเลือกจากชุดป้ายกำกับในตัวของ OpenClaw -แบบคำเดียวตามด้วยจุดไข่ปลา: +ที่เป็นคำเดียวพร้อมจุดไข่ปลา: ```text Thinking... @@ -180,8 +179,8 @@ Surfacing... ## ควบคุมบรรทัดความคืบหน้า บรรทัดความคืบหน้าเปิดใช้โดยค่าเริ่มต้นในโหมดความคืบหน้า บรรทัดเหล่านี้มาจากเหตุการณ์การทำงานจริง: -การเริ่มใช้เครื่องมือ การอัปเดตรายการ แผนงาน การอนุมัติ เอาต์พุตคำสั่ง สรุป -patch และกิจกรรม agent ที่คล้ายกัน +การเริ่มเครื่องมือ การอัปเดตรายการ แผนงาน การอนุมัติ เอาต์พุตคำสั่ง สรุปแพตช์ +และกิจกรรมเอเจนต์ที่คล้ายกัน OpenClaw ใช้ตัวจัดรูปแบบเดียวกันสำหรับร่างความคืบหน้าและ `/verbose`: @@ -195,17 +194,17 @@ OpenClaw ใช้ตัวจัดรูปแบบเดียวกัน } ``` -`"explain"` เป็นค่าเริ่มต้น และทำให้ร่างมีความคงที่ด้วยป้ายกำกับกระชับ เช่น -`🛠️ Exec: check JS syntax for /tmp/app.js` `"raw"` จะต่อท้าย -คำสั่ง/รายละเอียดพื้นฐานเมื่อมี ซึ่งมีประโยชน์ขณะดีบักแต่รบกวนมากกว่าใน +`"explain"` เป็นค่าเริ่มต้นและทำให้ร่างนิ่งด้วยป้ายกำกับกระชับ เช่น +`🛠️ Exec: check JS syntax for /tmp/app.js` ส่วน `"raw"` จะผนวก +คำสั่ง/รายละเอียดเบื้องหลังเมื่อมี ซึ่งมีประโยชน์ขณะดีบักแต่มีเสียงรบกวนมากกว่าใน แชต ตัวอย่างเช่น คำสั่งเดียวกันจะปรากฏต่างกันตามโหมดรายละเอียด: -| โหมด | บรรทัดความคืบหน้า | +| โหมด | บรรทัดความคืบหน้า | | --------- | -------------------------------------------------------------------- | -| `explain` | `🛠️ Exec: check JS syntax for /tmp/app.js` | -| `raw` | `🛠️ Exec: check JS syntax for /tmp/app.js, node --check /tmp/app.js` | +| `explain` | `🛠️ Exec: check JS syntax for /tmp/app.js` | +| `raw` | `🛠️ Exec: check JS syntax for /tmp/app.js, node --check /tmp/app.js` | จำกัดจำนวนบรรทัดที่ยังมองเห็นได้: @@ -224,7 +223,34 @@ OpenClaw ใช้ตัวจัดรูปแบบเดียวกัน } ``` -คงร่างความคืบหน้าเดี่ยวไว้ แต่ซ่อนบรรทัดเครื่องมือและงาน: +บรรทัดความคืบหน้าจะถูกบีบอัดโดยอัตโนมัติเพื่อลดการจัดเรียงฟองแชตใหม่ขณะที่มีการแก้ไขร่าง + +OpenClaw ตัดบรรทัดความคืบหน้าที่ยาวโดยค่าเริ่มต้น เพื่อไม่ให้การแก้ไขร่างซ้ำๆ +ตัดบรรทัดต่างกันทุกครั้งที่อัปเดต คำนำหน้ายังคงอ่านได้ และรายละเอียดที่ยาว +เช่น พาธหรือคำสั่งดิบจะถูกย่อด้วยจุดไข่ปลา + +Slack สามารถแสดงบรรทัดความคืบหน้าเป็นฟิลด์ Block Kit แบบมีโครงสร้างแทน +เนื้อความข้อความเดียว: + +```json5 +{ + channels: { + slack: { + streaming: { + mode: "progress", + progress: { + render: "rich", + }, + }, + }, + }, +} +``` + +การแสดงผลแบบ rich ยังคงมี fallback แบบข้อความล้วนเดียวกัน เพื่อให้ช่องทางและไคลเอนต์ที่ +ไม่รองรับรูปแบบที่สมบูรณ์กว่า ยังสามารถแสดงข้อความความคืบหน้าแบบกะทัดรัดได้ + +คงร่างความคืบหน้าเดียวไว้แต่ซ่อนบรรทัดเครื่องมือและงาน: ```json5 { @@ -241,77 +267,77 @@ OpenClaw ใช้ตัวจัดรูปแบบเดียวกัน } ``` -ด้วย `toolProgress: false` OpenClaw ยังคงระงับข้อความ -ความคืบหน้าของเครื่องมือแบบแยกเดิมสำหรับเทิร์นนั้น ช่องทางจะยังดูเงียบ -จนกว่าจะมีคำตอบสุดท้าย ยกเว้นป้ายกำกับหากมีการกำหนดค่าไว้ +เมื่อใช้ `toolProgress: false` OpenClaw ยังคงระงับข้อความ +ความคืบหน้าของเครื่องมือแบบเดี่ยวรุ่นเก่าสำหรับเทิร์นนั้น ช่องทางจะยังคงเงียบในเชิงภาพจนกว่า +คำตอบสุดท้าย ยกเว้นป้ายกำกับถ้ามีการกำหนดค่าไว้ ## พฤติกรรมของช่องทาง -แต่ละช่องทางใช้ transport ที่สะอาดที่สุดที่รองรับ: +แต่ละช่องทางใช้การขนส่งที่สะอาดที่สุดที่รองรับ: -| ช่องทาง | transport ความคืบหน้า | หมายเหตุ | +| ช่องทาง | การขนส่งความคืบหน้า | หมายเหตุ | | --------------- | -------------------------------------- | --------------------------------------------------------------------- | -| Discord | ส่งหนึ่งข้อความ แล้วแก้ไขข้อความนั้น | ข้อความสุดท้ายจะแก้ไขในตำแหน่งเดิมเมื่อพอดีกับข้อความพรีวิวที่ปลอดภัยหนึ่งข้อความ | -| Matrix | ส่งหนึ่ง event แล้วแก้ไข event นั้น | การกำหนดค่าสตรีมระดับบัญชีควบคุมร่างระดับบัญชี | -| Microsoft Teams | สตรีม Teams แบบ native ในแชตส่วนตัว | `streaming.mode: "block"` แมปไปยังการส่งแบบบล็อกของ Teams | -| Slack | สตรีมแบบ native หรือโพสต์ร่างที่แก้ไขได้ | ความพร้อมของ thread ส่งผลต่อว่าสามารถใช้สตรีมแบบ native ได้หรือไม่ | -| Telegram | ส่งหนึ่งข้อความ แล้วแก้ไขข้อความนั้น | ร่างเก่าที่มองเห็นได้อาจถูกแทนที่ เพื่อให้เวลาประทับสุดท้ายยังมีประโยชน์ | -| Mattermost | โพสต์ร่างที่แก้ไขได้ | กิจกรรมเครื่องมือถูกรวมเข้าในโพสต์แบบร่างเดียวกัน | +| Discord | ส่งข้อความหนึ่งข้อความ แล้วแก้ไขข้อความนั้น | ข้อความสุดท้ายแก้ไขแทนที่เดิมเมื่อพอดีกับข้อความตัวอย่างที่ปลอดภัยหนึ่งข้อความ | +| Matrix | ส่งเหตุการณ์หนึ่งรายการ แล้วแก้ไขเหตุการณ์นั้น | การกำหนดค่าสตรีมระดับบัญชีควบคุมร่างระดับบัญชี | +| Microsoft Teams | สตรีม Teams แบบเนทีฟในแชตส่วนตัว | `streaming.mode: "block"` แมปไปยังการส่งแบบบล็อกของ Teams | +| Slack | สตรีมเนทีฟหรือโพสต์ร่างที่แก้ไขได้ | ความพร้อมใช้งานของเธรดมีผลต่อว่าจะใช้การสตรีมเนทีฟได้หรือไม่ | +| Telegram | ส่งข้อความหนึ่งข้อความ แล้วแก้ไขข้อความนั้น | ร่างเก่าที่มองเห็นได้อาจถูกแทนที่เพื่อให้เวลาประทับสุดท้ายยังมีประโยชน์ | +| Mattermost | โพสต์ร่างที่แก้ไขได้ | กิจกรรมเครื่องมือถูกรวมเข้าในโพสต์แบบร่างเดียวกัน | -ช่องทางที่ไม่มีการรองรับการแก้ไขอย่างปลอดภัยมักถอยกลับไปใช้ตัวบ่งชี้การพิมพ์หรือ +ช่องทางที่ไม่รองรับการแก้ไขอย่างปลอดภัยมักจะ fallback ไปเป็นตัวบ่งชี้การพิมพ์หรือ การส่งเฉพาะคำตอบสุดท้าย -## การปิดท้าย +## การสรุปผล -เมื่อคำตอบสุดท้ายพร้อม OpenClaw จะพยายามรักษาแชตให้สะอาด: +เมื่อคำตอบสุดท้ายพร้อม OpenClaw จะพยายามทำให้แชตสะอาด: -- หากร่างสามารถกลายเป็นคำตอบสุดท้ายได้อย่างปลอดภัย OpenClaw จะแก้ไขร่างนั้นในตำแหน่งเดิม -- หากช่องทางใช้การสตรีมความคืบหน้าแบบ native OpenClaw จะปิดท้ายสตรีมนั้น - เมื่อ transport แบบ native รับข้อความสุดท้าย -- หากคำตอบสุดท้ายมีสื่อ พรอมต์อนุมัติ เป้าหมายการตอบกลับที่ระบุชัด - มีจำนวนก้อนมากเกินไป หรือการแก้ไข/ส่งล้มเหลว OpenClaw จะส่งคำตอบสุดท้ายผ่าน - เส้นทางการส่งปกติของช่องทาง +- หากร่างสามารถกลายเป็นคำตอบสุดท้ายได้อย่างปลอดภัย OpenClaw จะแก้ไขร่างนั้นแทนที่เดิม +- หากช่องทางใช้การสตรีมความคืบหน้าแบบเนทีฟ OpenClaw จะสรุปสตรีมนั้น + เมื่อการขนส่งเนทีฟยอมรับข้อความสุดท้าย +- หากคำตอบสุดท้ายมีสื่อ พรอมป์ขออนุมัติ เป้าหมายการตอบกลับที่ระบุชัดเจน + มีจำนวนชิ้นมากเกินไป หรือแก้ไข/ส่งไม่สำเร็จ OpenClaw จะส่งคำตอบสุดท้ายผ่าน + เส้นทางการส่งของช่องทางปกติ -เส้นทาง fallback เป็นความตั้งใจ การส่งคำตอบสุดท้ายใหม่ดีกว่า -การทำข้อความหาย ตอบผิด thread หรือเขียนทับร่างด้วย payload ที่ช่องทาง -ไม่สามารถแสดงแทนได้อย่างปลอดภัย +เส้นทาง fallback เป็นสิ่งที่ตั้งใจไว้ การส่งคำตอบสุดท้ายใหม่ดีกว่า +การสูญเสียข้อความ การตอบผิดเธรด หรือการเขียนทับร่างด้วย payload ที่ช่องทาง +ไม่สามารถแทนได้อย่างปลอดภัย -## การแก้ปัญหา +## การแก้ไขปัญหา **ฉันเห็นเฉพาะคำตอบสุดท้าย** -ตรวจสอบว่า `channels..streaming.mode` ตั้งค่าเป็น `progress` สำหรับ -บัญชีหรือช่องทางที่จัดการข้อความนั้น เส้นทางบางแบบของกลุ่มหรือการตอบกลับแบบอ้างอิงอาจ -ปิดใช้พรีวิวร่างสำหรับเทิร์นหนึ่งเมื่อช่องทางไม่สามารถแก้ไขข้อความที่ถูกต้องได้อย่างปลอดภัย +ตรวจสอบว่า `channels..streaming.mode` ถูกตั้งค่าเป็น `progress` สำหรับ +บัญชีหรือช่องทางที่จัดการข้อความนั้น เส้นทางกลุ่มหรือการตอบกลับแบบอ้างอิงบางอย่างอาจ +ปิดใช้ตัวอย่างร่างสำหรับเทิร์นหนึ่งเมื่อช่องทางไม่สามารถแก้ไขข้อความที่ถูกต้องได้อย่างปลอดภัย **ฉันเห็นป้ายกำกับแต่ไม่มีบรรทัดเครื่องมือ** ตรวจสอบ `streaming.progress.toolProgress` หากเป็น `false` OpenClaw จะคง -พฤติกรรมร่างเดี่ยวไว้ แต่ซ่อนบรรทัดความคืบหน้าของเครื่องมือและงาน +พฤติกรรมร่างเดียวไว้แต่ซ่อนบรรทัดความคืบหน้าของเครื่องมือและงาน -**ฉันเห็นข้อความสุดท้ายใหม่แทนร่างที่ถูกแก้ไข** +**ฉันเห็นข้อความสุดท้ายใหม่แทนที่จะเป็นร่างที่แก้ไขแล้ว** -นั่นคือ fallback เพื่อความปลอดภัย สิ่งนี้อาจเกิดขึ้นกับการตอบกลับที่มีสื่อ คำตอบยาว -เป้าหมายการตอบกลับที่ระบุชัด ร่าง Telegram เก่า เป้าหมาย thread ของ Slack ที่ขาดหาย -ข้อความพรีวิวที่ถูกลบ หรือการปิดท้ายสตรีมแบบ native ที่ล้มเหลว +นั่นคือ fallback ด้านความปลอดภัย อาจเกิดขึ้นกับคำตอบที่มีสื่อ คำตอบยาว +เป้าหมายการตอบกลับที่ระบุชัดเจน ร่าง Telegram เก่า เป้าหมายเธรด Slack ที่หายไป +ข้อความตัวอย่างที่ถูกลบ หรือการสรุปสตรีมเนทีฟที่ล้มเหลว -**ฉันยังเห็นข้อความความคืบหน้าแบบแยกอยู่** +**ฉันยังเห็นข้อความความคืบหน้าแบบเดี่ยว** -โหมดความคืบหน้าจะระงับข้อความความคืบหน้าของเครื่องมือแบบแยกตามค่าเริ่มต้นเมื่อร่าง -กำลังทำงานอยู่ หากข้อความแยกยังปรากฏ ให้ตรวจสอบว่าเทิร์นนั้นกำลัง +โหมดความคืบหน้าจะระงับข้อความความคืบหน้าของเครื่องมือแบบเดี่ยวเริ่มต้นเมื่อร่าง +กำลังใช้งานอยู่ หากข้อความแบบเดี่ยวยังปรากฏ ให้ตรวจสอบว่าเทิร์นนั้นกำลัง ใช้โหมดความคืบหน้าจริง ไม่ใช่ `streaming.mode: "off"` หรือเส้นทางช่องทางที่ ไม่สามารถสร้างร่างสำหรับข้อความนั้นได้ **Teams ทำงานต่างจาก Discord หรือ Telegram** -Microsoft Teams ใช้สตรีมแบบ native ในแชตส่วนตัว แทน transport พรีวิว -แบบส่งแล้วแก้ไขทั่วไป Teams ยังถือว่า `streaming.mode: "block"` เป็น -การส่งแบบบล็อกของ Teams เพราะไม่มีโหมดบล็อกพรีวิวร่างแบบเดียวกับ -ที่ Discord และ Telegram ใช้ +Microsoft Teams ใช้สตรีมเนทีฟในแชตส่วนตัวแทนการขนส่งตัวอย่างแบบ +ส่งแล้วแก้ไขทั่วไป นอกจากนี้ Teams ยังถือว่า `streaming.mode: "block"` เป็น +การส่งแบบบล็อกของ Teams เพราะไม่มีโหมดบล็อกตัวอย่างร่างแบบเดียวกับที่ +Discord และ Telegram ใช้ ## ที่เกี่ยวข้อง -- [การสตรีมและการแบ่งก้อน](/th/concepts/streaming) +- [การสตรีมและการแบ่งชิ้น](/th/concepts/streaming) - [ข้อความ](/th/concepts/messages) - [การกำหนดค่าช่องทาง](/th/gateway/config-channels) - [Discord](/th/channels/discord) diff --git a/docs/th/concepts/qa-e2e-automation.md b/docs/th/concepts/qa-e2e-automation.md index 5b6d243db..563842b34 100644 --- a/docs/th/concepts/qa-e2e-automation.md +++ b/docs/th/concepts/qa-e2e-automation.md @@ -1,33 +1,34 @@ --- read_when: - ทำความเข้าใจว่าสแต็ก QA เชื่อมโยงกันอย่างไร - - การขยาย qa-lab, qa-channel หรืออะแดปเตอร์การขนส่ง - - การเพิ่มสถานการณ์ QA ที่อิงกับรีโป - - การสร้างระบบอัตโนมัติด้านการประกันคุณภาพที่สมจริงยิ่งขึ้นสำหรับแดชบอร์ด Gateway -summary: 'ภาพรวมสแต็ก QA: qa-lab, qa-channel, สถานการณ์ที่อิง repo, ช่องทางการขนส่งแบบ live, อะแดปเตอร์การขนส่ง และการรายงาน.' -title: ภาพรวมการประกันคุณภาพ + - การขยาย qa-lab, qa-channel หรืออะแดปเตอร์การรับส่งข้อมูล + - การเพิ่มสถานการณ์ QA ที่อ้างอิงจากรีโป + - การสร้างระบบอัตโนมัติ QA ที่สมจริงยิ่งขึ้นรอบแดชบอร์ด Gateway +summary: 'ภาพรวมสแต็ก QA: qa-lab, qa-channel, สถานการณ์ที่รองรับด้วยรีโป, เลนการส่งผ่านแบบสด, อะแดปเตอร์การส่งผ่าน และการรายงาน.' +title: ภาพรวม QA x-i18n: - generated_at: "2026-05-04T02:23:57Z" + generated_at: "2026-05-04T07:05:07Z" model: gpt-5.5 provider: openai - source_hash: 0b376767b967a51cc8a45ca5ce420f78067b52e6368d2abe921ffed533f6f9ba + source_hash: 067f5aa0831724659ae36d548ef2e7bd28b40aad9cef45f325a01a2748003b29 source_path: concepts/qa-e2e-automation.md workflow: 16 --- -สแตก QA ส่วนตัวมีไว้เพื่อทดสอบ OpenClaw ในรูปแบบที่สมจริงและมีลักษณะเหมือนช่องทางมากกว่าที่ unit test เดี่ยวจะทำได้ +Private QA stack มีไว้เพื่อทดสอบ OpenClaw ในลักษณะที่สมจริงกว่าและมีรูปทรงตามช่องทาง +มากกว่าที่ unit test เดียวจะทำได้ -ส่วนประกอบปัจจุบัน: +ชิ้นส่วนปัจจุบัน: -- `extensions/qa-channel`: ช่องทางข้อความสังเคราะห์ที่มีพื้นผิว DM, ช่องทาง, เธรด, - รีแอ็กชัน, การแก้ไข และการลบ +- `extensions/qa-channel`: ช่องทางข้อความสังเคราะห์ที่มีพื้นผิว DM, channel, thread, + reaction, edit และ delete - `extensions/qa-lab`: UI ดีบักเกอร์และบัส QA สำหรับสังเกต transcript, แทรกข้อความขาเข้า และส่งออกรายงาน Markdown -- `extensions/qa-matrix`, Plugin ตัวรันเนอร์ในอนาคต: อะแดปเตอร์ live-transport ที่ - ขับช่องทางจริงภายใน Gateway QA ย่อย -- `qa/`: แอสเซต seed ที่รองรับโดยรีโปสำหรับงาน kickoff และสถานการณ์ QA +- `extensions/qa-matrix`, Plugin รันเนอร์ในอนาคต: อะแดปเตอร์ live-transport ที่ + ขับช่องทางจริงภายใน child QA gateway +- `qa/`: แอสเซ็ต seed ที่อิงกับ repo สำหรับงานเริ่มต้นและสถานการณ์ QA baseline -- [Mantis](/th/concepts/mantis): การตรวจสอบแบบ live ก่อนและหลังสำหรับบั๊กที่ +- [Mantis](/th/concepts/mantis): การยืนยันสดก่อนและหลังสำหรับบั๊กที่ ต้องใช้ transport จริง, ภาพหน้าจอเบราว์เซอร์, สถานะ VM และหลักฐาน PR ## พื้นผิวคำสั่ง @@ -35,33 +36,33 @@ x-i18n: ทุกโฟลว์ QA ทำงานภายใต้ `pnpm openclaw qa ` หลายรายการมี alias สคริปต์ `pnpm qa:*`; รองรับทั้งสองรูปแบบ -| คำสั่ง | วัตถุประสงค์ | -| --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `qa run` | self-check QA ที่บันเดิลมา; เขียนรายงาน Markdown | -| `qa suite` | รันสถานการณ์ที่รองรับโดยรีโปกับเลน Gateway QA Alias: `pnpm openclaw qa suite --runner multipass` สำหรับ Linux VM แบบใช้แล้วทิ้ง | -| `qa coverage` | พิมพ์ inventory ความครอบคลุมของสถานการณ์ใน markdown (`--json` สำหรับเอาต์พุตสำหรับเครื่อง) | -| `qa parity-report` | เปรียบเทียบไฟล์ `qa-suite-summary.json` สองไฟล์และเขียนรายงาน parity แบบ agentic | -| `qa character-eval` | รันสถานการณ์ QA ด้านคาแรกเตอร์กับโมเดล live หลายตัวพร้อมรายงานที่มีการตัดสิน ดู [การรายงาน](#reporting) | -| `qa manual` | รัน prompt แบบครั้งเดียวกับเลน provider/model ที่เลือก | -| `qa ui` | เริ่ม UI ดีบักเกอร์ QA และบัส QA ภายในเครื่อง (alias: `pnpm qa:lab:ui`) | -| `qa docker-build-image` | สร้างอิมเมจ Docker QA ที่ prebake ไว้ | -| `qa docker-scaffold` | เขียน scaffold docker-compose สำหรับแดชบอร์ด QA + เลน Gateway | -| `qa up` | สร้างไซต์ QA, เริ่มสแตกที่รองรับด้วย Docker, พิมพ์ URL (alias: `pnpm qa:lab:up`; variant `:fast` เพิ่ม `--use-prebuilt-image --bind-ui-dist --skip-ui-build`) | -| `qa aimock` | เริ่มเฉพาะเซิร์ฟเวอร์ provider AIMock | -| `qa mock-openai` | เริ่มเฉพาะเซิร์ฟเวอร์ provider `mock-openai` ที่รู้จักสถานการณ์ | -| `qa credentials doctor` / `add` / `list` / `remove` | จัดการพูล credential Convex ที่ใช้ร่วมกัน | -| `qa matrix` | เลน transport live กับ homeserver Tuwunel แบบใช้แล้วทิ้ง ดู [Matrix QA](/th/concepts/qa-matrix) | -| `qa telegram` | เลน transport live กับกลุ่ม Telegram ส่วนตัวจริง | -| `qa discord` | เลน transport live กับช่อง guild Discord ส่วนตัวจริง | -| `qa slack` | เลน transport live กับช่อง Slack ส่วนตัวจริง | -| `qa mantis` | ตัวรันตรวจสอบก่อนและหลังสำหรับบั๊ก transport live พร้อมหลักฐาน status-reactions ของ Discord และ smoke เดสก์ท็อป/เบราว์เซอร์ Crabbox ดู [Mantis](/th/concepts/mantis) | +| คำสั่ง | วัตถุประสงค์ | +| --------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `qa run` | self-check QA ที่บันเดิลมา; เขียนรายงาน Markdown | +| `qa suite` | รันสถานการณ์ที่อิงกับ repo กับเลน QA gateway Alias: `pnpm openclaw qa suite --runner multipass` สำหรับ Linux VM แบบใช้แล้วทิ้ง | +| `qa coverage` | พิมพ์ inventory coverage ของสถานการณ์ในรูปแบบ markdown (`--json` สำหรับเอาต์พุตเครื่อง) | +| `qa parity-report` | เปรียบเทียบไฟล์ `qa-suite-summary.json` สองไฟล์และเขียนรายงาน agentic parity | +| `qa character-eval` | รันสถานการณ์ character QA ข้ามโมเดลสดหลายตัวพร้อมรายงานที่มีการตัดสิน ดู [การรายงาน](#reporting) | +| `qa manual` | รัน prompt แบบครั้งเดียวกับเลน provider/model ที่เลือกไว้ | +| `qa ui` | เริ่ม UI ดีบักเกอร์ QA และบัส QA ในเครื่อง (alias: `pnpm qa:lab:ui`) | +| `qa docker-build-image` | สร้างอิมเมจ QA Docker ที่อบไว้ล่วงหน้า | +| `qa docker-scaffold` | เขียน scaffold docker-compose สำหรับแดชบอร์ด QA + เลน gateway | +| `qa up` | สร้างไซต์ QA, เริ่ม stack ที่อิงกับ Docker, พิมพ์ URL (alias: `pnpm qa:lab:up`; variant `:fast` เพิ่ม `--use-prebuilt-image --bind-ui-dist --skip-ui-build`) | +| `qa aimock` | เริ่มเฉพาะเซิร์ฟเวอร์ provider AIMock | +| `qa mock-openai` | เริ่มเฉพาะเซิร์ฟเวอร์ provider `mock-openai` ที่รับรู้สถานการณ์ | +| `qa credentials doctor` / `add` / `list` / `remove` | จัดการ pool credential Convex ที่ใช้ร่วมกัน | +| `qa matrix` | เลน live transport กับ Tuwunel homeserver แบบใช้แล้วทิ้ง ดู [Matrix QA](/th/concepts/qa-matrix) | +| `qa telegram` | เลน live transport กับกลุ่ม Telegram ส่วนตัวจริง | +| `qa discord` | เลน live transport กับช่อง guild Discord ส่วนตัวจริง | +| `qa slack` | เลน live transport กับช่อง Slack ส่วนตัวจริง | +| `qa mantis` | รันเนอร์การยืนยันก่อนและหลังสำหรับบั๊ก live transport พร้อมหลักฐาน status-reactions ของ Discord, smoke เดสก์ท็อป/เบราว์เซอร์ Crabbox และ smoke Slack-in-VNC ดู [Mantis](/th/concepts/mantis) | ## โฟลว์ผู้ปฏิบัติการ -โฟลว์ผู้ปฏิบัติการ QA ปัจจุบันเป็นไซต์ QA แบบสองพาเนล: +โฟลว์ผู้ปฏิบัติการ QA ปัจจุบันคือไซต์ QA แบบสอง pane: - ซ้าย: แดชบอร์ด Gateway (Control UI) พร้อม agent -- ขวา: QA Lab แสดง transcript แบบคล้าย Slack และแผนสถานการณ์ +- ขวา: QA Lab แสดง transcript แบบ Slack-ish และแผนสถานการณ์ รันด้วย: @@ -69,12 +70,13 @@ x-i18n: pnpm qa:lab:up ``` -คำสั่งนั้นสร้างไซต์ QA, เริ่มเลน Gateway ที่รองรับด้วย Docker และเปิดหน้า -QA Lab ซึ่งผู้ปฏิบัติการหรือ automation loop สามารถให้ภารกิจ QA กับ agent, -สังเกตพฤติกรรมช่องทางจริง และบันทึกว่าสิ่งใดทำงาน ล้มเหลว หรือยังถูกบล็อก +คำสั่งนี้สร้างไซต์ QA, เริ่มเลน gateway ที่อิงกับ Docker และเปิดเผยหน้า +QA Lab ที่ผู้ปฏิบัติการหรือลูปอัตโนมัติสามารถมอบภารกิจ QA ให้ agent, +สังเกตพฤติกรรมช่องทางจริง และบันทึกสิ่งที่ทำงานได้ ล้มเหลว หรือ +ยังติดบล็อกอยู่ -สำหรับการวนปรับ UI ของ QA Lab ภายในเครื่องให้เร็วขึ้นโดยไม่ต้องสร้างอิมเมจ Docker ใหม่ทุกครั้ง, -ให้เริ่มสแตกด้วยบันเดิล QA Lab แบบ bind-mounted: +สำหรับการวนแก้ UI ของ QA Lab ในเครื่องให้เร็วขึ้นโดยไม่ต้องสร้างอิมเมจ Docker ใหม่ทุกครั้ง, +ให้เริ่ม stack ด้วยบันเดิล QA Lab แบบ bind-mounted: ```bash pnpm openclaw qa docker-build-image @@ -84,39 +86,39 @@ pnpm qa:lab:watch ``` `qa:lab:up:fast` คงบริการ Docker ไว้บนอิมเมจที่สร้างไว้ล่วงหน้าและ bind-mount -`extensions/qa-lab/web/dist` เข้าในคอนเทนเนอร์ `qa-lab` ส่วน `qa:lab:watch` -จะสร้างบันเดิลนั้นใหม่เมื่อมีการเปลี่ยนแปลง และเบราว์เซอร์จะ reload อัตโนมัติเมื่อ hash แอสเซต QA Lab +`extensions/qa-lab/web/dist` เข้าไปใน container `qa-lab` `qa:lab:watch` +สร้างบันเดิลนั้นใหม่เมื่อมีการเปลี่ยนแปลง และเบราว์เซอร์จะโหลดซ้ำอัตโนมัติเมื่อ hash แอสเซ็ต QA Lab เปลี่ยนไป -สำหรับ smoke trace OpenTelemetry ภายในเครื่อง ให้รัน: +สำหรับ smoke trace OpenTelemetry ในเครื่อง ให้รัน: ```bash pnpm qa:otel:smoke ``` -สคริปต์นั้นเริ่มตัวรับ trace OTLP/HTTP ภายในเครื่อง, รันสถานการณ์ QA -`otel-trace-smoke` โดยเปิดใช้ Plugin `diagnostics-otel` จากนั้น -decode protobuf spans ที่ export แล้วตรวจยืนยันรูปร่างที่สำคัญต่อ release: +สคริปต์นั้นเริ่ม receiver trace OTLP/HTTP ในเครื่อง, รันสถานการณ์ QA +`otel-trace-smoke` โดยเปิดใช้งาน Plugin `diagnostics-otel`, จากนั้น +ถอดรหัส protobuf spans ที่ส่งออกและ assert รูปทรงที่สำคัญต่อ release: ต้องมี `openclaw.run`, `openclaw.harness.run`, `openclaw.model.call`, `openclaw.context.assembled` และ `openclaw.message.delivery`; -การเรียกโมเดลต้องไม่ export `StreamAbandoned` ในเทิร์นที่สำเร็จ; raw diagnostic IDs และ -แอตทริบิวต์ `openclaw.content.*` ต้องไม่อยู่ใน trace โดยเขียน -`otel-smoke-summary.json` ไว้ถัดจาก artifacts ของ QA suite +model calls ต้องไม่ส่งออก `StreamAbandoned` ใน turn ที่สำเร็จ; ID diagnostic ดิบและ +attribute `openclaw.content.*` ต้องไม่อยู่ใน trace คำสั่งนี้เขียน +`otel-smoke-summary.json` ข้าง artifacts ของ QA suite -Observability QA ใช้ได้เฉพาะจาก source checkout เท่านั้น npm tarball จงใจละเว้น -QA Lab ดังนั้นเลน Docker release ของแพ็กเกจจึงไม่รันคำสั่ง `qa` ใช้ +QA ด้าน observability ยังคงเป็น source-checkout เท่านั้น npm tarball จงใจละเว้น +QA Lab ดังนั้นเลน release Docker ของแพ็กเกจจะไม่รันคำสั่ง `qa` ใช้ `pnpm qa:otel:smoke` จาก source checkout ที่ build แล้วเมื่อเปลี่ยน instrumentation -ด้าน diagnostics +diagnostics -สำหรับเลน smoke Matrix ที่ใช้ transport จริง ให้รัน: +สำหรับเลน smoke Matrix ที่เป็น transport จริง ให้รัน: ```bash pnpm openclaw qa matrix --profile fast --fail-fast ``` -เอกสารอ้างอิง CLI ฉบับเต็ม, แคตตาล็อก profile/scenario, env vars และเลย์เอาต์ artifact สำหรับเลนนี้อยู่ใน [Matrix QA](/th/concepts/qa-matrix) โดยสรุป: มัน provision homeserver Tuwunel แบบใช้แล้วทิ้งใน Docker, ลงทะเบียนผู้ใช้ driver/SUT/observer ชั่วคราว, รัน Plugin Matrix จริงภายใน Gateway QA ย่อยที่ scope กับ transport นั้น (ไม่มี `qa-channel`) จากนั้นเขียนรายงาน Markdown, สรุป JSON, artifact observed-events และ log เอาต์พุตรวมภายใต้ `.artifacts/qa-e2e/matrix-/` +เอกสารอ้างอิง CLI ฉบับเต็ม, catalog ของ profile/scenario, env vars และ layout artifact สำหรับเลนนี้อยู่ใน [Matrix QA](/th/concepts/qa-matrix) สรุปโดยย่อ: คำสั่งนี้ provision Tuwunel homeserver แบบใช้แล้วทิ้งใน Docker, ลงทะเบียนผู้ใช้ driver/SUT/observer ชั่วคราว, รัน Plugin Matrix จริงภายใน child QA gateway ที่จำกัดขอบเขตไว้กับ transport นั้น (ไม่มี `qa-channel`), จากนั้นเขียนรายงาน Markdown, summary JSON, artifact observed-events และ log เอาต์พุตรวมไว้ใต้ `.artifacts/qa-e2e/matrix-/` -สำหรับเลน smoke Telegram, Discord และ Slack ที่ใช้ transport จริง: +สำหรับเลน smoke Telegram, Discord และ Slack ที่เป็น transport จริง: ```bash pnpm openclaw qa telegram @@ -124,92 +126,109 @@ pnpm openclaw qa discord pnpm openclaw qa slack ``` -เลนเหล่านี้เล็งไปที่ช่องทางจริงที่มีอยู่แล้วพร้อมบอตสองตัว (driver + SUT) env vars ที่จำเป็น, รายการสถานการณ์, output artifacts และพูล credential Convex มีเอกสารอยู่ใน [เอกสารอ้างอิง QA สำหรับ Telegram, Discord และ Slack](#telegram-discord-and-slack-qa-reference) ด้านล่าง +เลนเหล่านี้มุ่งเป้าไปที่ช่องทางจริงที่มีอยู่แล้วพร้อม bot สองตัว (driver + SUT) env vars ที่จำเป็น, รายการสถานการณ์, output artifacts และ pool credential Convex มีเอกสารอยู่ใน [เอกสารอ้างอิง QA ของ Telegram, Discord และ Slack](#telegram-discord-and-slack-qa-reference) ด้านล่าง -ก่อนใช้ credential live แบบ pooled ให้รัน: +สำหรับการรัน Slack desktop VM เต็มรูปแบบพร้อม VNC rescue ให้รัน: + +```bash +pnpm openclaw qa mantis slack-desktop-smoke \ + --gateway-setup \ + --scenario slack-canary \ + --keep-lease +``` + +คำสั่งนั้นเช่าเครื่องเดสก์ท็อป/เบราว์เซอร์ Crabbox, รันเลนสด Slack +ภายใน VM, เปิด Slack Web ในเบราว์เซอร์ VNC, จับภาพเดสก์ท็อป และ +คัดลอก `slack-qa/` พร้อม `slack-desktop-smoke.png` กลับไปยังไดเรกทอรี artifact +ของ Mantis ใช้ `--lease-id ` ซ้ำหลังจากล็อกอิน Slack Web ด้วยตนเอง +ผ่าน VNC เมื่อใช้ `--gateway-setup` Mantis จะคง Gateway Slack ของ OpenClaw +แบบถาวรที่ทำงานอยู่ภายใน VM บนพอร์ต `38973`; ถ้าไม่ใช้ คำสั่งจะรัน +เลน QA Slack แบบ bot-to-bot ปกติและออกหลังจากจับ artifact แล้ว + +ก่อนใช้ credential สดจาก pool ให้รัน: ```bash pnpm openclaw qa credentials doctor ``` -doctor ตรวจ env ของ broker Convex, ตรวจสอบการตั้งค่า endpoint และตรวจยืนยันว่าเข้าถึง admin/list ได้เมื่อมี secret ของ maintainer อยู่ โดยรายงานเฉพาะสถานะตั้งค่าแล้ว/ขาดหายสำหรับ secrets +doctor ตรวจสอบ env ของ broker Convex, validate การตั้งค่า endpoint และยืนยันการเข้าถึง admin/list เมื่อมี maintainer secret อยู่ โดยจะรายงานเฉพาะสถานะ set/missing สำหรับ secrets -## ความครอบคลุม transport live +## Coverage ของ live transport -เลน transport live ใช้ contract เดียวร่วมกันแทนที่แต่ละเลนจะประดิษฐ์รูปร่างรายการสถานการณ์ของตัวเอง `qa-channel` เป็นชุดทดสอบพฤติกรรมผลิตภัณฑ์สังเคราะห์แบบกว้างและไม่เป็นส่วนหนึ่งของเมทริกซ์ความครอบคลุม transport live +เลน live transport ใช้ contract เดียวกันแทนที่แต่ละเลนจะสร้างรูปทรงรายการสถานการณ์ของตัวเอง `qa-channel` คือ suite พฤติกรรมผลิตภัณฑ์สังเคราะห์แบบกว้าง และไม่ได้เป็นส่วนหนึ่งของ matrix coverage ของ live transport -| เลน | Canary | Mention gating | Bot-to-bot | บล็อก allowlist | การตอบกลับระดับบนสุด | กลับมาทำต่อหลัง restart | follow-up ของเธรด | การแยกเธรด | การสังเกตรีแอ็กชัน | คำสั่งช่วยเหลือ | การลงทะเบียนคำสั่ง native | +| เลน | Canary | การ gate mention | Bot-to-bot | บล็อก allowlist | การตอบกลับระดับบนสุด | resume หลัง restart | follow-up ใน thread | isolation ของ thread | การสังเกต reaction | คำสั่ง help | การลงทะเบียนคำสั่ง native | | -------- | ------ | -------------- | ---------- | --------------- | --------------- | -------------- | ---------------- | ---------------- | -------------------- | ------------ | --------------------------- | | Matrix | x | x | x | x | x | x | x | x | x | | | | Telegram | x | x | x | | | | | | | x | | | Discord | x | x | x | | | | | | | | x | | Slack | x | x | x | | | | | | | | | -สิ่งนี้คง `qa-channel` ไว้เป็นชุดทดสอบพฤติกรรมผลิตภัณฑ์แบบกว้าง ขณะที่ Matrix, -Telegram และ transport live ในอนาคตใช้ checklist transport-contract ที่ชัดเจนร่วมกัน +สิ่งนี้คง `qa-channel` ไว้เป็น suite พฤติกรรมผลิตภัณฑ์แบบกว้าง ขณะที่ Matrix, +Telegram และ live transports ในอนาคตใช้ checklist transport-contract ที่ชัดเจนร่วมกัน -สำหรับเลน Linux VM แบบใช้แล้วทิ้งโดยไม่ต้องนำ Docker เข้ามาในเส้นทาง QA ให้รัน: +สำหรับเลน Linux VM แบบใช้แล้วทิ้งโดยไม่ดึง Docker เข้ามาในเส้นทาง QA ให้รัน: ```bash pnpm openclaw qa suite --runner multipass --scenario channel-chat-baseline ``` -คำสั่งนี้บูต guest Multipass ใหม่, ติดตั้ง dependency, build OpenClaw -ภายใน guest, รัน `qa suite` จากนั้นคัดลอกรายงาน QA และ -สรุปปกติกลับเข้า `.artifacts/qa-e2e/...` บน host -มันใช้พฤติกรรมการเลือกสถานการณ์เดียวกับ `qa suite` บน host -การรัน suite บน host และ Multipass จะ execute สถานการณ์ที่เลือกหลายรายการพร้อมกัน -ด้วย worker Gateway ที่แยกกันโดยค่าเริ่มต้น `qa-channel` ค่าเริ่มต้น concurrency -คือ 4 โดยถูก cap ตามจำนวนสถานการณ์ที่เลือก ใช้ `--concurrency ` เพื่อปรับ -จำนวน worker หรือ `--concurrency 1` สำหรับการ execute แบบ serial -คำสั่งจะ exit ด้วยค่าไม่เป็นศูนย์เมื่อสถานการณ์ใดล้มเหลว ใช้ `--allow-failures` เมื่อ -คุณต้องการ artifacts โดยไม่มี exit code ที่ล้มเหลว -การรัน live จะส่งต่ออินพุต auth ของ QA ที่รองรับและใช้ได้จริงสำหรับ -guest: provider keys ผ่าน env, path คอนฟิก QA live provider และ -`CODEX_HOME` เมื่อมีอยู่ คง `--output-dir` ไว้ภายใต้ root ของรีโปเพื่อให้ guest +คำสั่งนี้บูต Multipass guest ใหม่ ติดตั้ง dependency สร้าง OpenClaw +ภายใน guest รัน `qa suite` จากนั้นคัดลอกรายงาน QA ปกติและ +สรุปกลับไปยัง `.artifacts/qa-e2e/...` บน host +คำสั่งนี้ใช้พฤติกรรมการเลือก scenario เดียวกับ `qa suite` บน host +การรันชุดทดสอบบน host และ Multipass จะดำเนินการ scenario ที่เลือกหลายรายการแบบขนาน +ด้วย worker ของ Gateway ที่แยกกันโดยค่าเริ่มต้น `qa-channel` ตั้งค่าเริ่มต้นของ concurrency +เป็น 4 โดยจำกัดไม่เกินจำนวน scenario ที่เลือก ใช้ `--concurrency ` เพื่อปรับ +จำนวน worker หรือ `--concurrency 1` สำหรับการดำเนินการแบบลำดับเดียว +คำสั่งจะออกด้วยสถานะไม่เป็นศูนย์เมื่อ scenario ใดล้มเหลว ใช้ `--allow-failures` เมื่อ +คุณต้องการ artifact โดยไม่มี exit code ที่ล้มเหลว +การรันแบบ live จะส่งต่อ input การยืนยันตัวตน QA ที่รองรับและใช้งานได้จริงสำหรับ +guest ได้แก่ key ของ provider จาก env, path config ของ QA live provider และ +`CODEX_HOME` เมื่อมีอยู่ เก็บ `--output-dir` ไว้ใต้ repo root เพื่อให้ guest เขียนกลับผ่าน workspace ที่ mount ไว้ได้ -## เอกสารอ้างอิง QA สำหรับ Telegram, Discord และ Slack +## อ้างอิง QA สำหรับ Telegram, Discord และ Slack -Matrix มี [หน้าเฉพาะ](/th/concepts/qa-matrix) เนื่องจากจำนวนสถานการณ์และการ provision homeserver ที่รองรับด้วย Docker Telegram, Discord และ Slack มีขนาดเล็กกว่า — มีสถานการณ์ไม่กี่รายการต่อแต่ละตัว, ไม่มีระบบ profile, ทำงานกับช่องทางจริงที่มีอยู่แล้ว — ดังนั้นเอกสารอ้างอิงของพวกมันจึงอยู่ที่นี่ +Matrix มี[หน้าเฉพาะ](/th/concepts/qa-matrix)เนื่องจากมีจำนวน scenario มากและมีการจัดเตรียม homeserver ที่ใช้ Docker รองรับ Telegram, Discord และ Slack มีขนาดเล็กกว่า โดยมีเพียงไม่กี่ scenario ต่อรายการ ไม่มีระบบ profile และทดสอบกับ channel จริงที่มีอยู่แล้ว ดังนั้นอ้างอิงของรายการเหล่านี้จึงอยู่ที่นี่ -### แฟล็ก CLI ที่ใช้ร่วมกัน +### flag ของ CLI ที่ใช้ร่วมกัน -เลนเหล่านี้ลงทะเบียนผ่าน `extensions/qa-lab/src/live-transports/shared/live-transport-cli.ts` และรับแฟล็กเดียวกัน: +lane เหล่านี้ลงทะเบียนผ่าน `extensions/qa-lab/src/live-transports/shared/live-transport-cli.ts` และรับ flag เดียวกัน: -| แฟล็ก | ค่าเริ่มต้น | คำอธิบาย | +| Flag | ค่าเริ่มต้น | คำอธิบาย | | ------------------------------------- | --------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | -| `--scenario ` | — | เรียกใช้เฉพาะสถานการณ์นี้ ทำซ้ำได้ | -| `--output-dir ` | `/.artifacts/qa-e2e/{telegram,discord,slack}-` | ตำแหน่งที่เขียนรายงาน/สรุป/ข้อความที่สังเกตได้ และบันทึกเอาต์พุต พาธสัมพัทธ์จะอิงจาก `--repo-root` | -| `--repo-root ` | `process.cwd()` | รากของ repository เมื่อเรียกใช้จาก cwd ที่เป็นกลาง | -| `--sut-account ` | `sut` | ID บัญชีชั่วคราวภายในคอนฟิก Gateway ของ QA | -| `--provider-mode ` | `live-frontier` | `mock-openai` หรือ `live-frontier` (`live-openai` แบบเดิมยังใช้งานได้) | -| `--model ` / `--alt-model ` | ค่าเริ่มต้นของผู้ให้บริการ | การอ้างอิงโมเดลหลัก/สำรอง | -| `--fast` | ปิด | โหมดเร็วของผู้ให้บริการเมื่อรองรับ | -| `--credential-source ` | `env` | ดู [กลุ่มข้อมูลประจำตัว Convex](#convex-credential-pool) | -| `--credential-role ` | `ci` ใน CI, มิฉะนั้นเป็น `maintainer` | บทบาทที่ใช้เมื่อ `--credential-source convex` | +| `--scenario ` | — | รันเฉพาะ scenario นี้ ทำซ้ำได้ | +| `--output-dir ` | `/.artifacts/qa-e2e/{telegram,discord,slack}-` | ตำแหน่งที่เขียน report/summary/observed message และ output log path แบบ relative จะ resolve เทียบกับ `--repo-root` | +| `--repo-root ` | `process.cwd()` | root ของ repository เมื่อเรียกใช้จาก cwd ที่เป็นกลาง | +| `--sut-account ` | `sut` | id บัญชีชั่วคราวภายใน config ของ QA Gateway | +| `--provider-mode ` | `live-frontier` | `mock-openai` หรือ `live-frontier` (`live-openai` แบบ legacy ยังใช้งานได้) | +| `--model ` / `--alt-model ` | ค่าเริ่มต้นของ provider | ref ของ model หลัก/สำรอง | +| `--fast` | ปิด | โหมดเร็วของ provider ในที่ที่รองรับ | +| `--credential-source ` | `env` | ดู [pool ของ credential ใน Convex](#convex-credential-pool) | +| `--credential-role ` | `ci` ใน CI, นอกนั้นเป็น `maintainer` | role ที่ใช้เมื่อ `--credential-source convex` | -แต่ละ lane จะออกด้วยค่าที่ไม่ใช่ศูนย์เมื่อมีสถานการณ์ใดล้มเหลว `--allow-failures` จะเขียน artifacts โดยไม่ตั้งค่า exit code เป็นล้มเหลว +แต่ละ lane จะออกด้วยสถานะไม่เป็นศูนย์เมื่อ scenario ใดล้มเหลว `--allow-failures` จะเขียน artifact โดยไม่ตั้ง exit code ที่ล้มเหลว -### QA ของ Telegram +### Telegram QA ```bash pnpm openclaw qa telegram ``` -กำหนดเป้าหมายไปยังกลุ่ม Telegram ส่วนตัวจริงหนึ่งกลุ่มที่มีบอทแตกต่างกันสองตัว (driver + SUT) บอท SUT ต้องมีชื่อผู้ใช้ Telegram; การสังเกตแบบบอทถึงบอททำงานได้ดีที่สุดเมื่อบอททั้งสองเปิดใช้ **โหมดการสื่อสารแบบบอทถึงบอท** ใน `@BotFather` +เป้าหมายคือกลุ่ม Telegram ส่วนตัวจริงหนึ่งกลุ่มที่มี bot สองตัวแยกกัน (driver + SUT) SUT bot ต้องมี username ของ Telegram; การสังเกตการณ์ bot-to-bot ทำงานได้ดีที่สุดเมื่อ bot ทั้งสองตัวเปิดใช้ **Bot-to-Bot Communication Mode** ใน `@BotFather` env ที่จำเป็นเมื่อ `--credential-source env`: -- `OPENCLAW_QA_TELEGRAM_GROUP_ID` — ID แชตแบบตัวเลข (สตริง) +- `OPENCLAW_QA_TELEGRAM_GROUP_ID` — id ของ chat แบบตัวเลข (string) - `OPENCLAW_QA_TELEGRAM_DRIVER_BOT_TOKEN` - `OPENCLAW_QA_TELEGRAM_SUT_BOT_TOKEN` ตัวเลือกเสริม: -- `OPENCLAW_QA_TELEGRAM_CAPTURE_CONTENT=1` เก็บเนื้อหาข้อความไว้ใน artifacts ของข้อความที่สังเกตได้ (ค่าเริ่มต้นจะปกปิด) +- `OPENCLAW_QA_TELEGRAM_CAPTURE_CONTENT=1` เก็บเนื้อหาข้อความไว้ใน artifact ของ observed-message (ค่าเริ่มต้นจะ redact) -สถานการณ์ (`extensions/qa-lab/src/live-transports/telegram/telegram-live.runtime.ts:44`): +Scenario (`extensions/qa-lab/src/live-transports/telegram/telegram-live.runtime.ts:44`): - `telegram-canary` - `telegram-mention-gating` @@ -220,19 +239,19 @@ env ที่จำเป็นเมื่อ `--credential-source env`: - `telegram-whoami-command` - `telegram-context-command` -Artifacts เอาต์พุต: +Artifact ที่ส่งออก: - `telegram-qa-report.md` -- `telegram-qa-summary.json` — รวม RTT ต่อการตอบกลับ (driver ส่ง → สังเกตเห็น SUT ตอบกลับ) โดยเริ่มจาก canary -- `telegram-qa-observed-messages.json` — เนื้อหาถูกปกปิด เว้นแต่ `OPENCLAW_QA_TELEGRAM_CAPTURE_CONTENT=1` +- `telegram-qa-summary.json` — รวม RTT ต่อ reply (driver ส่ง → สังเกตเห็น SUT reply) เริ่มจาก canary +- `telegram-qa-observed-messages.json` — redact เนื้อหา เว้นแต่ตั้งค่า `OPENCLAW_QA_TELEGRAM_CAPTURE_CONTENT=1` -### QA ของ Discord +### Discord QA ```bash pnpm openclaw qa discord ``` -กำหนดเป้าหมายไปยังช่อง guild ส่วนตัวจริงหนึ่งช่องใน Discord ด้วยบอทสองตัว: บอท driver ที่ควบคุมโดย harness และบอท SUT ที่เริ่มโดย Gateway ลูกของ OpenClaw ผ่าน Plugin Discord ที่ bundled มา ตรวจสอบการจัดการการกล่าวถึงช่อง, การที่บอท SUT ลงทะเบียนคำสั่งเนทีฟ `/help` กับ Discord แล้ว, และสถานการณ์หลักฐาน Mantis แบบ opt-in +เป้าหมายคือ channel ของ Discord guild ส่วนตัวจริงหนึ่ง channel ที่มี bot สองตัว: driver bot ที่ควบคุมโดย harness และ SUT bot ที่เริ่มโดย child OpenClaw Gateway ผ่าน Plugin Discord ที่ bundle มา ตรวจสอบการจัดการการ mention ใน channel, การที่ SUT bot ลงทะเบียนคำสั่ง native `/help` กับ Discord แล้ว และ scenario หลักฐานของ Mantis แบบ opt-in env ที่จำเป็นเมื่อ `--credential-source env`: @@ -240,20 +259,20 @@ env ที่จำเป็นเมื่อ `--credential-source env`: - `OPENCLAW_QA_DISCORD_CHANNEL_ID` - `OPENCLAW_QA_DISCORD_DRIVER_BOT_TOKEN` - `OPENCLAW_QA_DISCORD_SUT_BOT_TOKEN` -- `OPENCLAW_QA_DISCORD_SUT_APPLICATION_ID` — ต้องตรงกับ ID ผู้ใช้ของบอท SUT ที่ Discord ส่งคืน (มิฉะนั้น lane จะล้มเหลวอย่างรวดเร็ว) +- `OPENCLAW_QA_DISCORD_SUT_APPLICATION_ID` — ต้องตรงกับ user id ของ SUT bot ที่ Discord ส่งคืน (ไม่เช่นนั้น lane จะล้มเหลวอย่างรวดเร็ว) ตัวเลือกเสริม: -- `OPENCLAW_QA_DISCORD_CAPTURE_CONTENT=1` เก็บเนื้อหาข้อความไว้ใน artifacts ของข้อความที่สังเกตได้ +- `OPENCLAW_QA_DISCORD_CAPTURE_CONTENT=1` เก็บเนื้อหาข้อความไว้ใน artifact ของ observed-message -สถานการณ์ (`extensions/qa-lab/src/live-transports/discord/discord-live.runtime.ts:36`): +Scenario (`extensions/qa-lab/src/live-transports/discord/discord-live.runtime.ts:36`): - `discord-canary` - `discord-mention-gating` - `discord-native-help-command-registration` -- `discord-status-reactions-tool-only` — สถานการณ์ Mantis แบบ opt-in ทำงานด้วยตัวเองเพราะจะสลับ SUT ให้ตอบกลับ guild แบบเปิดตลอดเวลาและใช้เฉพาะเครื่องมือด้วย `messages.statusReactions.enabled=true` จากนั้นจับไทม์ไลน์ reaction ผ่าน REST พร้อม artifact ภาพ HTML/PNG +- `discord-status-reactions-tool-only` — scenario ของ Mantis แบบ opt-in รันเดี่ยวเพราะจะสลับ SUT เป็นการ reply ใน guild แบบ always-on และ tool-only ด้วย `messages.statusReactions.enabled=true` จากนั้นจับ timeline ของ REST reaction พร้อม artifact ภาพ HTML/PNG -เรียกใช้สถานการณ์ status-reaction ของ Mantis อย่างชัดเจน: +รัน scenario status-reaction ของ Mantis โดยระบุอย่างชัดเจน: ```bash pnpm openclaw qa discord \ @@ -264,20 +283,20 @@ pnpm openclaw qa discord \ --fast ``` -Artifacts เอาต์พุต: +Artifact ที่ส่งออก: - `discord-qa-report.md` - `discord-qa-summary.json` -- `discord-qa-observed-messages.json` — เนื้อหาถูกปกปิด เว้นแต่ `OPENCLAW_QA_DISCORD_CAPTURE_CONTENT=1` -- `discord-qa-reaction-timelines.json` และ `discord-status-reactions-tool-only-timeline.png` เมื่อสถานการณ์ status-reaction ทำงาน +- `discord-qa-observed-messages.json` — redact เนื้อหา เว้นแต่ตั้งค่า `OPENCLAW_QA_DISCORD_CAPTURE_CONTENT=1` +- `discord-qa-reaction-timelines.json` และ `discord-status-reactions-tool-only-timeline.png` เมื่อรัน scenario status-reaction -### QA ของ Slack +### Slack QA ```bash pnpm openclaw qa slack ``` -กำหนดเป้าหมายไปยังช่อง Slack ส่วนตัวจริงหนึ่งช่องที่มีบอทแตกต่างกันสองตัว: บอท driver ที่ควบคุมโดย harness และบอท SUT ที่เริ่มโดย Gateway ลูกของ OpenClaw ผ่าน Plugin Slack ที่ bundled มา +เป้าหมายคือ channel ของ Slack ส่วนตัวจริงหนึ่ง channel ที่มี bot สองตัวแยกกัน: driver bot ที่ควบคุมโดย harness และ SUT bot ที่เริ่มโดย child OpenClaw Gateway ผ่าน Plugin Slack ที่ bundle มา env ที่จำเป็นเมื่อ `--credential-source env`: @@ -288,144 +307,147 @@ env ที่จำเป็นเมื่อ `--credential-source env`: ตัวเลือกเสริม: -- `OPENCLAW_QA_SLACK_CAPTURE_CONTENT=1` เก็บเนื้อหาข้อความไว้ใน artifacts ของข้อความที่สังเกตได้ +- `OPENCLAW_QA_SLACK_CAPTURE_CONTENT=1` เก็บเนื้อหาข้อความไว้ใน artifact ของ observed-message -สถานการณ์ (`extensions/qa-lab/src/live-transports/slack/slack-live.runtime.ts:39`): +Scenario (`extensions/qa-lab/src/live-transports/slack/slack-live.runtime.ts:39`): - `slack-canary` - `slack-mention-gating` -Artifacts เอาต์พุต: +Artifact ที่ส่งออก: - `slack-qa-report.md` - `slack-qa-summary.json` -- `slack-qa-observed-messages.json` — เนื้อหาถูกปกปิด เว้นแต่ `OPENCLAW_QA_SLACK_CAPTURE_CONTENT=1` +- `slack-qa-observed-messages.json` — redact เนื้อหา เว้นแต่ตั้งค่า `OPENCLAW_QA_SLACK_CAPTURE_CONTENT=1` -### กลุ่มข้อมูลประจำตัว Convex +### pool ของ credential ใน Convex -lane ของ Telegram, Discord, และ Slack สามารถเช่าข้อมูลประจำตัวจากกลุ่ม Convex ที่ใช้ร่วมกันแทนการอ่าน env vars ข้างต้นได้ ส่ง `--credential-source convex` (หรือตั้งค่า `OPENCLAW_QA_CREDENTIAL_SOURCE=convex`); QA Lab จะขอ lease แบบเอกสิทธิ์ ส่ง Heartbeat ตลอดช่วงเวลาการรัน และปล่อย lease เมื่อปิดระบบ ชนิดของกลุ่มคือ `"telegram"`, `"discord"`, และ `"slack"` +lane ของ Telegram, Discord และ Slack สามารถเช่า credential จาก pool ของ Convex ที่ใช้ร่วมกันแทนการอ่าน env var ข้างต้น ส่ง `--credential-source convex` (หรือตั้งค่า `OPENCLAW_QA_CREDENTIAL_SOURCE=convex`); QA Lab จะรับ lease แบบ exclusive, ส่ง Heartbeat ตลอดระยะเวลาการรัน และ release เมื่อ shutdown kind ของ pool คือ `"telegram"`, `"discord"` และ `"slack"` -รูปแบบ payload ที่ broker ตรวจสอบบน `admin/add`: +รูปทรง payload ที่ broker ตรวจสอบใน `admin/add`: -- Telegram (`kind: "telegram"`): `{ groupId: string, driverToken: string, sutToken: string }` — `groupId` ต้องเป็นสตริง chat-id แบบตัวเลข +- Telegram (`kind: "telegram"`): `{ groupId: string, driverToken: string, sutToken: string }` — `groupId` ต้องเป็น string ของ chat-id แบบตัวเลข - Discord (`kind: "discord"`): `{ guildId: string, channelId: string, driverBotToken: string, sutBotToken: string, sutApplicationId: string }` -env vars สำหรับปฏิบัติการและสัญญา endpoint ของ broker Convex อยู่ใน [การทดสอบ → ข้อมูลประจำตัว Telegram ที่ใช้ร่วมกันผ่าน Convex](/th/help/testing#shared-telegram-credentials-via-convex-v1) (ชื่อส่วนนี้มีมาก่อนการรองรับ Discord; ความหมายของ broker เหมือนกันสำหรับทั้งสองชนิด) +env var สำหรับการปฏิบัติงานและ contract endpoint ของ broker Convex อยู่ใน [การทดสอบ → credential Telegram ที่ใช้ร่วมกันผ่าน Convex](/th/help/testing#shared-telegram-credentials-via-convex-v1) (ชื่อ section เกิดก่อนการรองรับ Discord; semantic ของ broker เหมือนกันสำหรับทั้งสอง kind) -## Seeds ที่อิงจาก repo +## seed ที่รองรับด้วย repo -Seed assets อยู่ใน `qa/`: +asset ของ seed อยู่ใน `qa/`: - `qa/scenarios/index.md` - `qa/scenarios//*.md` -สิ่งเหล่านี้ตั้งใจให้อยู่ใน git เพื่อให้แผน QA มองเห็นได้ทั้งสำหรับมนุษย์และ -agent +สิ่งเหล่านี้ตั้งใจให้อยู่ใน git เพื่อให้ทั้งมนุษย์และ +agent มองเห็นแผน QA -`qa-lab` ควรยังคงเป็น runner markdown ทั่วไป ไฟล์ markdown ของแต่ละสถานการณ์คือ -แหล่งความจริงสำหรับการทดสอบหนึ่งครั้ง และควรกำหนด: +`qa-lab` ควรคงเป็น runner markdown ทั่วไป แต่ละไฟล์ markdown ของ scenario คือ +source of truth สำหรับการรันทดสอบหนึ่งครั้ง และควรกำหนด: -- metadata ของสถานการณ์ -- metadata หมวดหมู่, capability, lane, และความเสี่ยงแบบเลือกได้ -- refs ของเอกสารและโค้ด -- ข้อกำหนด Plugin แบบเลือกได้ -- patch คอนฟิก Gateway แบบเลือกได้ -- `qa-flow` ที่เรียกใช้ได้ +- metadata ของ scenario +- metadata ของ category, capability, lane และ risk แบบเสริม +- ref ของ docs และ code +- ข้อกำหนด Plugin แบบเสริม +- patch ของ config Gateway แบบเสริม +- `qa-flow` ที่ดำเนินการได้ -พื้นผิว runtime ที่ใช้ซ้ำได้ซึ่งรองรับ `qa-flow` สามารถคงความทั่วไป -และข้ามหลายส่วนได้ ตัวอย่างเช่น สถานการณ์ markdown สามารถรวม helper ฝั่ง transport -กับ helper ฝั่งเบราว์เซอร์ที่ขับ Control UI แบบฝังผ่าน -seam `browser.request` ของ Gateway ได้โดยไม่ต้องเพิ่ม runner แบบกรณีพิเศษ +พื้นผิว runtime ที่ใช้ซ้ำได้ซึ่งรองรับ `qa-flow` สามารถคงความเป็นทั่วไป +และข้ามส่วนงานได้ ตัวอย่างเช่น scenario markdown สามารถรวม helper ฝั่ง transport +กับ helper ฝั่ง browser ที่ขับ Control UI ที่ฝังไว้ผ่าน +seam `browser.request` ของ Gateway โดยไม่ต้องเพิ่ม runner แบบกรณีพิเศษ -ควรจัดกลุ่มไฟล์สถานการณ์ตาม capability ของผลิตภัณฑ์แทนที่จะตามโฟลเดอร์ source tree -ให้ ID สถานการณ์คงที่เมื่อย้ายไฟล์; ใช้ `docsRefs` และ `codeRefs` -เพื่อให้ตามรอยการ implement ได้ +ไฟล์ scenario ควรถูกจัดกลุ่มตาม capability ของผลิตภัณฑ์แทน folder ของ source tree +คง id ของ scenario ให้เสถียรเมื่อย้ายไฟล์; ใช้ `docsRefs` และ `codeRefs` +เพื่อ trace การ implementation รายการ baseline ควรกว้างพอที่จะครอบคลุม: -- แชต DM และช่อง -- พฤติกรรมของ thread +- chat แบบ DM และ channel +- พฤติกรรม thread - lifecycle ของ message action -- callbacks ของ cron -- การเรียกคืน memory -- การสลับโมเดล +- callback ของ Cron +- การ recall memory +- การสลับ model - การส่งต่อให้ subagent -- การอ่าน repo และการอ่านเอกสาร +- การอ่าน repo และการอ่าน docs - งาน build ขนาดเล็กหนึ่งงาน เช่น Lobster Invaders -## Lane mock ของผู้ให้บริการ +## lane ของ provider mock -`qa suite` มี lane mock ผู้ให้บริการแบบ local สอง lane: +`qa suite` มี lane provider mock ใน local สอง lane: -- `mock-openai` คือ mock ของ OpenClaw ที่รับรู้สถานการณ์ มันยังคงเป็น lane mock แบบกำหนดแน่นอนค่าเริ่มต้นสำหรับ QA ที่อิงจาก repo และ parity gates -- `aimock` เริ่ม server ผู้ให้บริการที่อิงจาก AIMock สำหรับความครอบคลุมของ protocol, fixture, record/replay, และ chaos เชิงทดลอง เป็นส่วนเสริมและไม่แทนที่ dispatcher สถานการณ์ `mock-openai` +- `mock-openai` คือ mock ของ OpenClaw ที่รับรู้ scenario ยังคงเป็น lane mock แบบกำหนดผลได้ + เริ่มต้นสำหรับ QA ที่รองรับด้วย repo และ parity gate +- `aimock` เริ่ม server ของ provider ที่รองรับด้วย AIMock สำหรับ protocol, + fixture, record/replay และ coverage แบบ chaos เชิงทดลอง เป็นส่วนเสริมและไม่ได้ + แทนที่ dispatcher ของ scenario `mock-openai` -การ implement provider-lane อยู่ใต้ `extensions/qa-lab/src/providers/` -ผู้ให้บริการแต่ละรายเป็นเจ้าของค่าเริ่มต้น, การเริ่ม server local, คอนฟิกโมเดล Gateway, -ความต้องการ staging ของ auth-profile, และ flag capability แบบ live/mock โค้ด suite และ -Gateway ที่ใช้ร่วมกันควร route ผ่าน provider registry แทนการ branch ตาม -ชื่อผู้ให้บริการ +implementation ของ provider-lane อยู่ใต้ `extensions/qa-lab/src/providers/` +แต่ละ provider เป็นเจ้าของค่าเริ่มต้นของตนเอง, การเริ่ม server local, config model ของ Gateway, +ความต้องการ staging ของ auth-profile และ flag capability แบบ live/mock code ของ suite และ +Gateway ที่ใช้ร่วมกันควร route ผ่าน registry ของ provider แทนการ branch ตาม +ชื่อ provider -## Transport adapters +## adapter ของ transport -`qa-lab` เป็นเจ้าของ seam transport ทั่วไปสำหรับสถานการณ์ QA แบบ markdown `qa-channel` คือ adapter ตัวแรกบน seam นั้น แต่เป้าหมายการออกแบบกว้างกว่า: channel จริงหรือสังเคราะห์ในอนาคตควร plug into suite runner เดียวกันแทนการเพิ่ม runner QA เฉพาะ transport +`qa-lab` เป็นเจ้าของ seam transport ทั่วไปสำหรับ scenario QA แบบ markdown `qa-channel` คือ adapter แรกบน seam นั้น แต่เป้าหมายการออกแบบกว้างกว่า: channel จริงหรือสังเคราะห์ในอนาคตควรเสียบเข้ากับ suite runner เดียวกันแทนการเพิ่ม runner QA เฉพาะ transport ในระดับสถาปัตยกรรม การแบ่งคือ: -- `qa-lab` เป็นเจ้าของการดำเนินการสถานการณ์ทั่วไป, concurrency ของ worker, การเขียน artifact, และการรายงาน -- transport adapter เป็นเจ้าของคอนฟิก Gateway, readiness, การสังเกต inbound และ outbound, transport actions, และสถานะ transport ที่ normalize แล้ว -- ไฟล์สถานการณ์ markdown ใต้ `qa/scenarios/` กำหนดการทดสอบ; `qa-lab` ให้พื้นผิว runtime ที่ใช้ซ้ำได้ซึ่งเรียกใช้ไฟล์เหล่านั้น +- `qa-lab` เป็นเจ้าของการดำเนินการ scenario ทั่วไป, concurrency ของ worker, การเขียน artifact และการรายงาน +- adapter ของ transport เป็นเจ้าของ config Gateway, readiness, การสังเกตการณ์ inbound และ outbound, action ของ transport และสถานะ transport ที่ normalize แล้ว +- ไฟล์ scenario markdown ใต้ `qa/scenarios/` กำหนดการรันทดสอบ; `qa-lab` ให้พื้นผิว runtime ที่ใช้ซ้ำได้เพื่อดำเนินการไฟล์เหล่านั้น ### การเพิ่ม channel -การเพิ่ม channel ให้ระบบ QA แบบ markdown ต้องมีสองสิ่งเท่านั้น: +การเพิ่ม channel ลงในระบบ QA markdown ต้องมีสองอย่างพอดี: -1. transport adapter สำหรับ channel -2. scenario pack ที่ทดสอบสัญญา channel +1. adapter ของ transport สำหรับ channel +2. pack ของ scenario ที่ทดสอบ contract ของ channel -อย่าเพิ่มรากคำสั่ง QA ระดับบนใหม่เมื่อ host `qa-lab` ที่ใช้ร่วมกันสามารถเป็นเจ้าของ flow ได้ +อย่าเพิ่ม root คำสั่ง QA ระดับบนสุดใหม่เมื่อ host `qa-lab` ที่ใช้ร่วมกันสามารถเป็นเจ้าของ flow ได้ -`qa-lab` เป็นเจ้าของกลไก host ที่ใช้ร่วมกัน: +`qa-lab` เป็นเจ้าของกลไกโฮสต์ที่ใช้ร่วมกัน: -- รากคำสั่ง `openclaw qa` -- การเริ่มและ teardown ของ suite -- concurrency ของ worker +- รูทคำสั่ง `openclaw qa` +- การเริ่มต้นและการปิดชุดทดสอบ +- ภาวะพร้อมกันของ worker - การเขียน artifact - การสร้างรายงาน -- การดำเนินการสถานการณ์ -- alias เพื่อ compatibility สำหรับสถานการณ์ `qa-channel` เก่า +- การดำเนินการ scenario +- นามแฝงความเข้ากันได้สำหรับ scenario `qa-channel` รุ่นเก่า -Runner plugins เป็นเจ้าของสัญญา transport: +Plugin ตัวรันเป็นเจ้าของสัญญาของ transport: -- วิธี mount `openclaw qa ` ใต้ราก `qa` ที่ใช้ร่วมกัน -- วิธีคอนฟิก Gateway สำหรับ transport นั้น -- วิธีตรวจ readiness -- วิธี inject เหตุการณ์ inbound -- วิธีสังเกตข้อความ outbound -- วิธีเปิดเผย transcripts และสถานะ transport ที่ normalize แล้ว -- วิธีดำเนินการ actions ที่อิงจาก transport -- วิธีจัดการ reset หรือ cleanup เฉพาะ transport +- วิธี mount `openclaw qa ` ใต้รูท `qa` ที่ใช้ร่วมกัน +- วิธีกำหนดค่า Gateway สำหรับ transport นั้น +- วิธีตรวจสอบความพร้อม +- วิธีฉีด event ขาเข้า +- วิธีสังเกตข้อความขาออก +- วิธีเปิดเผย transcript และสถานะ transport ที่ normalized แล้ว +- วิธีดำเนิน action ที่มี transport รองรับ +- วิธีจัดการการ reset หรือ cleanup เฉพาะ transport -เกณฑ์ขั้นต่ำในการนำ channel ใหม่มาใช้: +เกณฑ์ขั้นต่ำในการนำช่องทางใหม่มาใช้: -1. ให้ `qa-lab` เป็นเจ้าของ root `qa` ที่ใช้ร่วมกันต่อไป -2. นำ transport runner ไปใช้งานบนจุดเชื่อมของโฮสต์ `qa-lab` ที่ใช้ร่วมกัน -3. เก็บกลไกเฉพาะ transport ไว้ใน Plugin ของ runner หรือ harness ของ channel -4. เมานต์ runner เป็น `openclaw qa ` แทนการลงทะเบียนคำสั่ง root ที่แข่งขันกัน Plugin ของ runner ควรประกาศ `qaRunners` ใน `openclaw.plugin.json` และส่งออกอาร์เรย์ `qaRunnerCliRegistrations` ที่ตรงกันจาก `runtime-api.ts` ทำให้ `runtime-api.ts` เบาไว้; การทำงานของ CLI และ runner แบบ lazy ควรอยู่หลัง entrypoint แยกต่างหาก -5. เขียนหรือปรับสถานการณ์ markdown ภายใต้ไดเรกทอรี `qa/scenarios/` ตามธีม -6. ใช้ helper สถานการณ์แบบทั่วไปสำหรับสถานการณ์ใหม่ -7. รักษา alias สำหรับความเข้ากันได้เดิมให้ใช้งานได้ต่อไป เว้นแต่ repo กำลังทำ migration โดยตั้งใจ +1. ให้ `qa-lab` เป็นเจ้าของรูท `qa` ที่ใช้ร่วมกันต่อไป +2. Implement ตัวรัน transport บน seam โฮสต์ `qa-lab` ที่ใช้ร่วมกัน +3. เก็บกลไกเฉพาะ transport ไว้ภายใน Plugin ตัวรันหรือ harness ของช่องทาง +4. Mount ตัวรันเป็น `openclaw qa ` แทนการลงทะเบียนคำสั่งรูทที่แข่งขันกัน Plugin ตัวรันควรประกาศ `qaRunners` ใน `openclaw.plugin.json` และ export อาร์เรย์ `qaRunnerCliRegistrations` ที่ตรงกันจาก `runtime-api.ts` ให้ `runtime-api.ts` เบาไว้ ส่วน CLI แบบ lazy และการดำเนินการตัวรันควรอยู่หลัง entrypoint แยกต่างหาก +5. เขียนหรือปรับ scenario แบบ Markdown ใต้ไดเรกทอรี `qa/scenarios/` ตามธีม +6. ใช้ helper scenario แบบ generic สำหรับ scenario ใหม่ +7. รักษานามแฝงความเข้ากันได้ที่มีอยู่ให้ใช้งานได้ เว้นแต่ repo กำลังทำการ migration โดยตั้งใจ กฎการตัดสินใจเข้มงวด: -- ถ้าพฤติกรรมสามารถอธิบายได้ครั้งเดียวใน `qa-lab` ให้ใส่ไว้ใน `qa-lab` -- ถ้าพฤติกรรมขึ้นกับ channel transport หนึ่งรายการ ให้เก็บไว้ใน Plugin ของ runner หรือ harness ของ Plugin นั้น -- ถ้าสถานการณ์ต้องการความสามารถใหม่ที่มากกว่าหนึ่ง channel ใช้ได้ ให้เพิ่ม helper แบบทั่วไปแทน branch เฉพาะ channel ใน `suite.ts` -- ถ้าพฤติกรรมมีความหมายเฉพาะกับ transport เดียว ให้สถานการณ์เป็นแบบเฉพาะ transport และระบุเรื่องนั้นให้ชัดเจนในสัญญาของสถานการณ์ +- หากพฤติกรรมสามารถแสดงได้ครั้งเดียวใน `qa-lab` ให้ใส่ไว้ใน `qa-lab` +- หากพฤติกรรมขึ้นกับ transport ของช่องทางเดียว ให้เก็บไว้ใน Plugin ตัวรันนั้นหรือ harness ของ Plugin +- หาก scenario ต้องการ capability ใหม่ที่มากกว่าหนึ่งช่องทางสามารถใช้ได้ ให้เพิ่ม helper แบบ generic แทน branch เฉพาะช่องทางใน `suite.ts` +- หากพฤติกรรมมีความหมายเฉพาะกับ transport เดียวเท่านั้น ให้คง scenario นั้นเป็นแบบเฉพาะ transport และระบุให้ชัดเจนในสัญญาของ scenario -### ชื่อ helper ของสถานการณ์ +### ชื่อ helper ของ scenario -helper แบบทั่วไปที่แนะนำสำหรับสถานการณ์ใหม่: +helper แบบ generic ที่แนะนำสำหรับ scenario ใหม่: - `waitForTransportReady` - `waitForChannelReady` @@ -440,22 +462,22 @@ helper แบบทั่วไปที่แนะนำสำหรับส - `formatTransportTranscript` - `resetTransport` -alias สำหรับความเข้ากันได้ยังคงมีให้ใช้สำหรับสถานการณ์เดิม — `waitForQaChannelReady`, `waitForOutboundMessage`, `waitForNoOutbound`, `formatConversationTranscript`, `resetBus` — แต่การเขียนสถานการณ์ใหม่ควรใช้ชื่อแบบทั่วไป alias เหล่านี้มีไว้เพื่อหลีกเลี่ยงการ migration แบบบังคับพร้อมกันทั้งหมด ไม่ใช่โมเดลสำหรับอนาคต +นามแฝงความเข้ากันได้ยังพร้อมใช้งานสำหรับ scenario ที่มีอยู่ — `waitForQaChannelReady`, `waitForOutboundMessage`, `waitForNoOutbound`, `formatConversationTranscript`, `resetBus` — แต่การเขียน scenario ใหม่ควรใช้ชื่อแบบ generic นามแฝงเหล่านี้มีไว้เพื่อหลีกเลี่ยงการ migration แบบ flag-day ไม่ใช่โมเดลสำหรับอนาคต ## การรายงาน -`qa-lab` ส่งออกรายงานโปรโตคอล Markdown จากไทม์ไลน์ของ bus ที่สังเกตได้ +`qa-lab` export รายงานโปรโตคอล Markdown จาก timeline ของ bus ที่สังเกตได้ รายงานควรตอบว่า: - อะไรทำงานได้ - อะไรล้มเหลว -- อะไรยังถูกบล็อกอยู่ -- สถานการณ์ติดตามผลใดควรเพิ่ม +- อะไรยังคงถูกบล็อก +- scenario ติดตามผลใดที่ควรค่าแก่การเพิ่ม -สำหรับรายการสถานการณ์ที่มีอยู่ — ซึ่งมีประโยชน์เมื่อประเมินขนาดงานติดตามผลหรือเชื่อมต่อ transport ใหม่ — ให้รัน `pnpm openclaw qa coverage` (เพิ่ม `--json` สำหรับเอาต์พุตที่เครื่องอ่านได้) +สำหรับ inventory ของ scenario ที่พร้อมใช้งาน ซึ่งมีประโยชน์เมื่อประเมินขนาดงานติดตามผลหรือเชื่อม transport ใหม่ ให้รัน `pnpm openclaw qa coverage` (เพิ่ม `--json` สำหรับ output ที่ machine-readable) -สำหรับการตรวจสอบลักษณะตัวละครและสไตล์ ให้รันสถานการณ์เดียวกันกับ ref ของโมเดล live หลายรายการ -แล้วเขียนรายงาน Markdown ที่ผ่านการตัดสิน: +สำหรับการตรวจ character และ style ให้รัน scenario เดียวกันกับ ref ของโมเดล live หลายตัว +และเขียนรายงาน Markdown ที่ตัดสินแล้ว: ```bash pnpm openclaw qa character-eval \ @@ -474,42 +496,41 @@ pnpm openclaw qa character-eval \ --judge-concurrency 16 ``` -คำสั่งนี้รันโปรเซสลูกของ QA gateway ในเครื่อง ไม่ใช่ Docker สถานการณ์ character eval -ควรกำหนด persona ผ่าน `SOUL.md` จากนั้นรัน turn ผู้ใช้ตามปกติ -เช่น chat, ความช่วยเหลือใน workspace และงานไฟล์ขนาดเล็ก ไม่ควรบอกโมเดลผู้สมัคร -ว่ากำลังถูกประเมิน คำสั่งจะเก็บ transcript ฉบับเต็มแต่ละรายการ -บันทึกสถิติพื้นฐานของการรัน จากนั้นถามโมเดลผู้ตัดสินในโหมด fast พร้อมการให้เหตุผล -`xhigh` เมื่อรองรับ เพื่อจัดอันดับการรันตามความเป็นธรรมชาติ vibe และอารมณ์ขัน -ใช้ `--blind-judge-models` เมื่อเปรียบเทียบผู้ให้บริการ: prompt ของผู้ตัดสินยังคงได้รับ -transcript และสถานะการรันทุกอย่าง แต่ ref ของผู้สมัครจะถูกแทนที่ด้วย -ป้ายกำกับกลาง เช่น `candidate-01`; รายงานจะแมปอันดับกลับไปยัง ref จริงหลังจาก +คำสั่งนี้รันกระบวนการลูกของ Gateway QA ในเครื่อง ไม่ใช่ Docker scenario ประเมิน character +ควรตั้ง persona ผ่าน `SOUL.md` จากนั้นรัน turn ผู้ใช้ทั่วไป +เช่น แชต ความช่วยเหลือเกี่ยวกับ workspace และงานไฟล์เล็ก ๆ ไม่ควรบอกโมเดล candidate +ว่ากำลังถูกประเมิน คำสั่งจะเก็บ transcript เต็มแต่ละรายการ +บันทึกสถิติการรันพื้นฐาน แล้วถามโมเดล judge ในโหมด fast พร้อม +reasoning `xhigh` เมื่อรองรับ เพื่อจัดอันดับการรันตามความเป็นธรรมชาติ vibe และอารมณ์ขัน +ใช้ `--blind-judge-models` เมื่อเปรียบเทียบ provider: prompt ของ judge ยังได้รับ +ทุก transcript และสถานะการรัน แต่ ref ของ candidate จะถูกแทนที่ด้วย label กลาง +เช่น `candidate-01`; รายงานจะ map การจัดอันดับกลับไปยัง ref จริงหลังจาก parse แล้ว -การรันผู้สมัครมีค่าเริ่มต้นเป็น thinking `high` โดยใช้ `medium` สำหรับ GPT-5.5 และ `xhigh` -สำหรับ ref eval ของ OpenAI รุ่นเก่าที่รองรับ กำหนดทับผู้สมัครเฉพาะรายแบบ inline ด้วย -`--model provider/model,thinking=` `--thinking ` ยังคงตั้งค่า -fallback ส่วนกลาง และรูปแบบเก่า `--model-thinking ` ยังคง -เก็บไว้เพื่อความเข้ากันได้ -ref ผู้สมัครของ OpenAI มีค่าเริ่มต้นเป็นโหมด fast เพื่อให้ใช้ priority processing ในจุดที่ -ผู้ให้บริการรองรับ เพิ่ม `,fast`, `,no-fast` หรือ `,fast=false` แบบ inline เมื่อ -ผู้สมัครหรือผู้ตัดสินรายเดียวต้องการ override ส่ง `--fast` เฉพาะเมื่อคุณต้องการ -บังคับเปิดโหมด fast สำหรับโมเดลผู้สมัครทุกตัว ระยะเวลาของผู้สมัครและผู้ตัดสินจะ -ถูกบันทึกในรายงานสำหรับการวิเคราะห์ benchmark แต่ prompt ของผู้ตัดสินระบุอย่างชัดเจน +การรัน candidate ใช้ thinking ค่าเริ่มต้นเป็น `high` โดยใช้ `medium` สำหรับ GPT-5.5 และ `xhigh` +สำหรับ ref eval ของ OpenAI รุ่นเก่าที่รองรับ Override candidate เฉพาะรายการแบบ inline ด้วย +`--model provider/model,thinking=` ส่วน `--thinking ` ยังตั้งค่า +fallback ส่วนกลาง และรูปแบบเก่า `--model-thinking ` ยังคงไว้เพื่อความเข้ากันได้ +ref candidate ของ OpenAI ใช้โหมด fast เป็นค่าเริ่มต้นเพื่อใช้ priority processing ในที่ที่ +provider รองรับ เพิ่ม `,fast`, `,no-fast`, หรือ `,fast=false` แบบ inline เมื่อ +candidate หรือ judge รายเดียวต้องการ override ส่ง `--fast` เฉพาะเมื่อต้องการ +บังคับเปิดโหมด fast สำหรับโมเดล candidate ทุกตัว ระยะเวลาของ candidate และ judge +จะถูกบันทึกในรายงานสำหรับการวิเคราะห์ benchmark แต่ prompt ของ judge ระบุอย่างชัดเจน ว่าอย่าจัดอันดับตามความเร็ว -การรันโมเดลผู้สมัครและผู้ตัดสินมีค่า concurrency เริ่มต้นเป็น 16 ทั้งคู่ ลด -`--concurrency` หรือ `--judge-concurrency` เมื่อขีดจำกัดของผู้ให้บริการหรือแรงกดบน gateway -ในเครื่องทำให้การรันมีสัญญาณรบกวนมากเกินไป -เมื่อไม่ได้ส่ง `--model` ของผู้สมัคร character eval จะใช้ค่าเริ่มต้นเป็น +การรันโมเดล candidate และ judge ใช้ concurrency 16 เป็นค่าเริ่มต้น ลด +`--concurrency` หรือ `--judge-concurrency` เมื่อข้อจำกัดของ provider หรือแรงกดดันต่อ Gateway +ในเครื่องทำให้การรันมี noise มากเกินไป +เมื่อไม่ได้ส่ง candidate `--model` การประเมิน character จะใช้ค่าเริ่มต้นเป็น `openai/gpt-5.5`, `openai/gpt-5.2`, `openai/gpt-5`, `anthropic/claude-opus-4-6`, `anthropic/claude-sonnet-4-6`, `zai/glm-5.1`, -`moonshot/kimi-k2.5` และ +`moonshot/kimi-k2.5`, และ `google/gemini-3.1-pro-preview` เมื่อไม่ได้ส่ง `--model` -เมื่อไม่ได้ส่ง `--judge-model` ผู้ตัดสินจะใช้ค่าเริ่มต้นเป็น +เมื่อไม่ได้ส่ง `--judge-model` judge จะใช้ค่าเริ่มต้นเป็น `openai/gpt-5.5,thinking=xhigh,fast` และ `anthropic/claude-opus-4-6,thinking=high` ## เอกสารที่เกี่ยวข้อง - [QA แบบเมทริกซ์](/th/concepts/qa-matrix) -- [QA Channel](/th/channels/qa-channel) +- [ช่องทาง QA](/th/channels/qa-channel) - [การทดสอบ](/th/help/testing) - [แดชบอร์ด](/th/web/dashboard) diff --git a/docs/th/concepts/streaming.md b/docs/th/concepts/streaming.md index 1a4d261d2..4e69d53c6 100644 --- a/docs/th/concepts/streaming.md +++ b/docs/th/concepts/streaming.md @@ -1,29 +1,29 @@ --- read_when: - - อธิบายวิธีการทำงานของการสตรีมหรือการแบ่งเป็นส่วนย่อยในช่องทาง - - การเปลี่ยนลักษณะการทำงานของการสตรีมแบบบล็อกหรือการแบ่งส่วนของช่องทาง - - การดีบักการตอบกลับแบบบล็อกที่ซ้ำกัน/เร็วเกินไป หรือการสตรีมตัวอย่างช่องทาง -summary: พฤติกรรมการสตรีม + การแบ่งเป็นชิ้น (การตอบกลับแบบบล็อก, การสตรีมพรีวิวช่องทาง, การแมปโหมด) -title: การสตรีมและการแบ่งเป็นชิ้นข้อมูล + - อธิบายวิธีการทำงานของการสตรีมหรือการแบ่งเป็นชิ้นส่วนในช่องทาง + - การเปลี่ยนพฤติกรรมการสตรีมแบบบล็อกหรือการแบ่งเป็นชิ้นของช่องทาง + - การดีบักการตอบกลับแบบบล็อกที่ซ้ำ/เร็วเกินไป หรือการสตรีมตัวอย่างของช่องทาง +summary: พฤติกรรมการสตรีม + การแบ่งเป็นชิ้น (การตอบกลับแบบบล็อก, การสตรีมตัวอย่างช่องทาง, การแมปโหมด) +title: การสตรีมและการแบ่งเป็นชิ้น x-i18n: - generated_at: "2026-05-03T21:30:53Z" + generated_at: "2026-05-04T07:05:05Z" model: gpt-5.5 provider: openai - source_hash: 1335f4f5532060bd8bf839683a2b1fbab38f38887c5583135652b4753e0f6a50 + source_hash: ff7b6cd8127255352fe16fb746469e9828e7d5aea183d3799ab10cc768515bd1 source_path: concepts/streaming.md workflow: 16 --- -OpenClaw มีเลเยอร์สตรีมมิงแยกกันสองชั้น: +OpenClaw มีเลเยอร์การสตรีมสองชั้นที่แยกจากกัน: -- **สตรีมมิงแบบบล็อก (ช่องทาง):** ส่ง **บล็อก** ที่เสร็จแล้วออกไปขณะที่ผู้ช่วยกำลังเขียน ข้อความเหล่านี้เป็นข้อความช่องทางปกติ (ไม่ใช่ token deltas) -- **สตรีมมิงแบบพรีวิว (Telegram/Discord/Slack):** อัปเดต **ข้อความพรีวิว** ชั่วคราวระหว่างกำลังสร้างคำตอบ +- **การสตรีมแบบบล็อก (ช่องทาง):** ส่ง **บล็อก** ที่เสร็จแล้วขณะที่ผู้ช่วยเขียนอยู่ ข้อความเหล่านี้เป็นข้อความช่องทางปกติ (ไม่ใช่เดลตาโทเค็น) +- **การสตรีมตัวอย่าง (Telegram/Discord/Slack):** อัปเดต **ข้อความตัวอย่าง** ชั่วคราวระหว่างการสร้างคำตอบ -ปัจจุบันยัง **ไม่มีสตรีมมิง token-delta จริง** ไปยังข้อความช่องทาง สตรีมมิงแบบพรีวิวอิงข้อความ (ส่ง + แก้ไข/ต่อท้าย) +ปัจจุบันยังไม่มี **การสตรีมเดลตาโทเค็นจริง** ไปยังข้อความช่องทาง การสตรีมตัวอย่างอิงตามข้อความ (ส่ง + แก้ไข/ต่อท้าย) -## สตรีมมิงแบบบล็อก (ข้อความช่องทาง) +## การสตรีมแบบบล็อก (ข้อความช่องทาง) -สตรีมมิงแบบบล็อกส่งเอาต์พุตของผู้ช่วยเป็นชังก์หยาบ ๆ เมื่อพร้อมใช้งาน +การสตรีมแบบบล็อกส่งเอาต์พุตของผู้ช่วยเป็นชิ้นหยาบ ๆ เมื่อพร้อมใช้งาน ``` Model output @@ -35,183 +35,165 @@ Model output └─ channel send (block replies) ``` -คำอธิบาย: +คำอธิบายสัญลักษณ์: -- `text_delta/events`: อีเวนต์สตรีมของโมเดล (อาจมีแบบห่าง ๆ สำหรับโมเดลที่ไม่สตรีม) -- `chunker`: `EmbeddedBlockChunker` ที่ใช้ขอบเขต min/max + การตั้งค่า break preference -- `channel send`: ข้อความขาออกจริง (การตอบกลับแบบบล็อก) +- `text_delta/events`: เหตุการณ์สตรีมของโมเดล (อาจมีน้อยสำหรับโมเดลที่ไม่สตรีม) +- `chunker`: `EmbeddedBlockChunker` ที่ใช้ขอบเขตขั้นต่ำ/สูงสุด + การตั้งค่าแบ่ง +- `channel send`: ข้อความขาออกจริง (คำตอบแบบบล็อก) **การควบคุม:** - `agents.defaults.blockStreamingDefault`: `"on"`/`"off"` (ค่าเริ่มต้นคือปิด) -- การ override ระดับช่องทาง: `*.blockStreaming` (และตัวแปรต่อบัญชี) เพื่อบังคับ `"on"`/`"off"` ต่อช่องทาง +- การเขียนทับระดับช่องทาง: `*.blockStreaming` (และรูปแบบต่อบัญชี) เพื่อบังคับ `"on"`/`"off"` ต่อช่องทาง - `agents.defaults.blockStreamingBreak`: `"text_end"` หรือ `"message_end"` - `agents.defaults.blockStreamingChunk`: `{ minChars, maxChars, breakPreference? }` - `agents.defaults.blockStreamingCoalesce`: `{ minChars?, maxChars?, idleMs? }` (รวมบล็อกที่สตรีมก่อนส่ง) -- เพดานสูงสุดของช่องทาง: `*.textChunkLimit` (เช่น `channels.whatsapp.textChunkLimit`) -- โหมดชังก์ของช่องทาง: `*.chunkMode` (`length` เป็นค่าเริ่มต้น, `newline` แยกตามบรรทัดว่าง (ขอบเขตย่อหน้า) ก่อนแยกตามความยาว) -- เพดานแบบนุ่มของ Discord: `channels.discord.maxLinesPerMessage` (ค่าเริ่มต้น 17) แยกการตอบกลับที่สูงเพื่อหลีกเลี่ยงการถูกตัดใน UI +- เพดานตายตัวของช่องทาง: `*.textChunkLimit` (เช่น `channels.whatsapp.textChunkLimit`) +- โหมดการแบ่งชิ้นของช่องทาง: `*.chunkMode` (`length` เป็นค่าเริ่มต้น, `newline` แบ่งตามบรรทัดว่าง (ขอบเขตย่อหน้า) ก่อนแบ่งตามความยาว) +- เพดานแบบยืดหยุ่นของ Discord: `channels.discord.maxLinesPerMessage` (ค่าเริ่มต้น 17) แบ่งคำตอบที่สูงเพื่อหลีกเลี่ยงการถูกตัดใน UI **ความหมายของขอบเขต:** -- `text_end`: สตรีมบล็อกทันทีที่ chunker ส่งออก; flush ในแต่ละ `text_end` -- `message_end`: รอจนข้อความผู้ช่วยจบ แล้วจึง flush เอาต์พุตที่ buffer ไว้ +- `text_end`: สตรีมบล็อกทันทีที่ตัวแบ่งชิ้นส่งออกมา; ล้างบัฟเฟอร์เมื่อถึงแต่ละ `text_end` +- `message_end`: รอจนข้อความผู้ช่วยเสร็จสิ้น แล้วจึงล้างเอาต์พุตที่บัฟเฟอร์ไว้ -`message_end` ยังคงใช้ chunker ถ้าข้อความที่ buffer ไว้เกิน `maxChars` ดังนั้นจึงอาจส่งออกได้หลายชังก์ในตอนท้าย +`message_end` ยังคงใช้ตัวแบ่งชิ้นหากข้อความที่บัฟเฟอร์ไว้เกิน `maxChars` ดังนั้นจึงอาจส่งออกหลายชิ้นในตอนท้ายได้ -### การส่งสื่อด้วยสตรีมมิงแบบบล็อก +### การส่งสื่อด้วยการสตรีมแบบบล็อก -คำสั่ง `MEDIA:` เป็นเมตาดาต้าการส่งตามปกติ เมื่อสตรีมมิงแบบบล็อกส่ง -บล็อกสื่อออกไปก่อน OpenClaw จะจดจำการส่งนั้นสำหรับเทิร์นนี้ ถ้า payload สุดท้าย -ของผู้ช่วยมี URL สื่อเดียวกันซ้ำ การส่งสุดท้ายจะตัดสื่อที่ซ้ำออก -แทนการส่งไฟล์แนบอีกครั้ง +คำสั่ง `MEDIA:` เป็นเมตาดาต้าการส่งปกติ เมื่อการสตรีมแบบบล็อกส่งบล็อกสื่อตั้งแต่เนิ่น ๆ OpenClaw จะจดจำการส่งนั้นไว้สำหรับเทิร์นดังกล่าว หากเพย์โหลดผู้ช่วยสุดท้ายซ้ำ URL สื่อเดียวกัน การส่งสุดท้ายจะตัดสื่อที่ซ้ำออกแทนที่จะส่งไฟล์แนบอีกครั้ง -payload สุดท้ายที่ซ้ำกันทุกประการจะถูกระงับ ถ้า payload สุดท้ายเพิ่ม -ข้อความที่แตกต่างรอบสื่อที่สตรีมไปแล้ว OpenClaw ยังส่ง -ข้อความใหม่โดยคงสื่อให้มีการส่งเพียงครั้งเดียว วิธีนี้ป้องกัน voice notes -หรือไฟล์ซ้ำบนช่องทางอย่าง Telegram เมื่อ agent ส่ง `MEDIA:` ระหว่าง -สตรีมมิงและ provider รวมสิ่งนั้นไว้ในคำตอบที่เสร็จแล้วด้วย +เพย์โหลดสุดท้ายที่ซ้ำกันทุกประการจะถูกระงับ หากเพย์โหลดสุดท้ายเพิ่มข้อความที่แตกต่างรอบสื่อที่สตรีมไปแล้ว OpenClaw จะยังส่งข้อความใหม่ขณะคงให้สื่อถูกส่งเพียงครั้งเดียว สิ่งนี้ป้องกันโน้ตเสียงหรือไฟล์ซ้ำบนช่องทางอย่าง Telegram เมื่อเอเจนต์ส่ง `MEDIA:` ระหว่างสตรีม และผู้ให้บริการรวมสิ่งนั้นไว้ในคำตอบที่เสร็จสมบูรณ์ด้วย -## อัลกอริทึมการแบ่งชังก์ (ขอบเขตต่ำ/สูง) +## อัลกอริทึมการแบ่งชิ้น (ขอบเขตต่ำ/สูง) -การแบ่งชังก์แบบบล็อกถูกใช้งานโดย `EmbeddedBlockChunker`: +การแบ่งชิ้นแบบบล็อกดำเนินการโดย `EmbeddedBlockChunker`: -- **ขอบเขตต่ำ:** อย่าส่งออกจนกว่า buffer >= `minChars` (เว้นแต่ถูกบังคับ) -- **ขอบเขตสูง:** เลือกแยกก่อน `maxChars`; ถ้าถูกบังคับ ให้แยกที่ `maxChars` -- **การตั้งค่า break preference:** `paragraph` → `newline` → `sentence` → `whitespace` → hard break -- **Code fences:** ไม่แยกภายใน fences; เมื่อถูกบังคับที่ `maxChars` ให้ปิด + เปิด fence ใหม่เพื่อให้ Markdown ยังถูกต้อง +- **ขอบเขตต่ำ:** อย่าส่งออกจนกว่าบัฟเฟอร์ >= `minChars` (ยกเว้นเมื่อถูกบังคับ) +- **ขอบเขตสูง:** เลือกแบ่งก่อน `maxChars`; หากถูกบังคับ ให้แบ่งที่ `maxChars` +- **การตั้งค่าแบ่ง:** `paragraph` → `newline` → `sentence` → `whitespace` → แบ่งแบบแข็ง +- **รั้วโค้ด:** ไม่แบ่งภายในรั้วเด็ดขาด; เมื่อถูกบังคับที่ `maxChars` ให้ปิด + เปิดรั้วใหม่เพื่อให้ Markdown ยังคงถูกต้อง -`maxChars` ถูก clamp ตาม `textChunkLimit` ของช่องทาง ดังนั้นคุณจึงไม่สามารถเกินเพดานต่อช่องทางได้ +`maxChars` ถูกจำกัดไว้ที่ `textChunkLimit` ของช่องทาง ดังนั้นคุณจึงไม่สามารถเกินเพดานต่อช่องทางได้ -## การรวมชังก์ (รวมบล็อกที่สตรีม) +## การรวมชิ้น (รวมบล็อกที่สตรีม) -เมื่อเปิดใช้งานสตรีมมิงแบบบล็อก OpenClaw สามารถ **รวมชังก์บล็อกที่ต่อเนื่องกัน** -ก่อนส่งออกได้ วิธีนี้ลด “สแปมบรรทัดเดียว” ในขณะที่ยังคงให้ -เอาต์พุตแบบค่อยเป็นค่อยไป +เมื่อเปิดใช้การสตรีมแบบบล็อก OpenClaw สามารถ **รวมชิ้นบล็อกที่ต่อเนื่องกัน** ก่อนส่งออกได้ สิ่งนี้ช่วยลด “สแปมบรรทัดเดียว” ขณะที่ยังคงให้เอาต์พุตแบบค่อยเป็นค่อยไป -- การรวมชังก์รอ **ช่วงว่างที่ idle** (`idleMs`) ก่อน flush -- Buffer ถูกจำกัดด้วย `maxChars` และจะ flush ถ้าเกินค่านั้น -- `minChars` ป้องกันไม่ให้ส่งส่วนย่อยที่เล็กมากจนกว่าจะสะสมข้อความได้พอ - (final flush จะส่งข้อความที่เหลือเสมอ) -- ตัวเชื่อมได้มาจาก `blockStreamingChunk.breakPreference` +- การรวมชิ้นจะรอ **ช่วงว่างที่ไม่มีความเคลื่อนไหว** (`idleMs`) ก่อนล้างบัฟเฟอร์ +- บัฟเฟอร์ถูกจำกัดด้วย `maxChars` และจะล้างหากเกินค่านั้น +- `minChars` ป้องกันไม่ให้ส่งเศษข้อความเล็ก ๆ จนกว่าจะสะสมข้อความได้เพียงพอ (การล้างครั้งสุดท้ายจะส่งข้อความที่เหลือเสมอ) +- ตัวเชื่อมมาจาก `blockStreamingChunk.breakPreference` (`paragraph` → `\n\n`, `newline` → `\n`, `sentence` → เว้นวรรค) -- การ override ระดับช่องทางใช้ได้ผ่าน `*.blockStreamingCoalesce` (รวมถึง config ต่อบัญชี) -- ค่าเริ่มต้นของการรวมชังก์ `minChars` ถูกเพิ่มเป็น 1500 สำหรับ Signal/Slack/Discord เว้นแต่จะ override +- การเขียนทับระดับช่องทางพร้อมใช้งานผ่าน `*.blockStreamingCoalesce` (รวมถึงการกำหนดค่าต่อบัญชี) +- ค่าเริ่มต้น `minChars` ของการรวมชิ้นถูกเพิ่มเป็น 1500 สำหรับ Signal/Slack/Discord เว้นแต่จะถูกเขียนทับ -## จังหวะเว้นระหว่างบล็อกแบบเหมือนมนุษย์ +## จังหวะระหว่างบล็อกที่เหมือนมนุษย์ -เมื่อเปิดใช้งานสตรีมมิงแบบบล็อก คุณสามารถเพิ่ม **การหยุดแบบสุ่ม** ระหว่าง -การตอบกลับแบบบล็อก (หลังบล็อกแรก) ได้ วิธีนี้ทำให้คำตอบแบบหลาย bubble ดู -เป็นธรรมชาติมากขึ้น +เมื่อเปิดใช้การสตรีมแบบบล็อก คุณสามารถเพิ่ม **การหยุดแบบสุ่ม** ระหว่างคำตอบแบบบล็อก (หลังบล็อกแรก) ได้ สิ่งนี้ทำให้คำตอบแบบหลายบับเบิลรู้สึกเป็นธรรมชาติมากขึ้น -- Config: `agents.defaults.humanDelay` (override ต่อ agent ผ่าน `agents.list[].humanDelay`) +- การกำหนดค่า: `agents.defaults.humanDelay` (เขียนทับต่อเอเจนต์ได้ผ่าน `agents.list[].humanDelay`) - โหมด: `off` (ค่าเริ่มต้น), `natural` (800–2500ms), `custom` (`minMs`/`maxMs`) -- ใช้กับ **การตอบกลับแบบบล็อก** เท่านั้น ไม่ใช่การตอบกลับสุดท้ายหรือสรุปเครื่องมือ +- ใช้กับ **คำตอบแบบบล็อก** เท่านั้น ไม่ใช้กับคำตอบสุดท้ายหรือสรุปเครื่องมือ -## "สตรีมชังก์หรือทุกอย่าง" +## "สตรีมเป็นชิ้นหรือทั้งหมด" สิ่งนี้แมปเป็น: -- **สตรีมชังก์:** `blockStreamingDefault: "on"` + `blockStreamingBreak: "text_end"` (ส่งออกไปเรื่อย ๆ) ช่องทางที่ไม่ใช่ Telegram ยังต้องมี `*.blockStreaming: true` ด้วย -- **สตรีมทุกอย่างตอนท้าย:** `blockStreamingBreak: "message_end"` (flush หนึ่งครั้ง อาจเป็นหลายชังก์ถ้ายาวมาก) -- **ไม่มีสตรีมมิงแบบบล็อก:** `blockStreamingDefault: "off"` (เฉพาะการตอบกลับสุดท้าย) +- **สตรีมเป็นชิ้น:** `blockStreamingDefault: "on"` + `blockStreamingBreak: "text_end"` (ส่งออกไปเรื่อย ๆ) ช่องทางที่ไม่ใช่ Telegram ต้องมี `*.blockStreaming: true` ด้วย +- **สตรีมทั้งหมดเมื่อจบ:** `blockStreamingBreak: "message_end"` (ล้างครั้งเดียว อาจเป็นหลายชิ้นหากยาวมาก) +- **ไม่ใช้การสตรีมแบบบล็อก:** `blockStreamingDefault: "off"` (เฉพาะคำตอบสุดท้าย) -**หมายเหตุช่องทาง:** สตรีมมิงแบบบล็อกจะ **ปิด เว้นแต่** -`*.blockStreaming` ถูกตั้งเป็น `true` อย่างชัดเจน ช่องทางสามารถสตรีมพรีวิวสด -(`channels..streaming`) ได้โดยไม่มีการตอบกลับแบบบล็อก +**หมายเหตุช่องทาง:** การสตรีมแบบบล็อกจะ **ปิดอยู่ เว้นแต่** +จะตั้งค่า `*.blockStreaming` เป็น `true` อย่างชัดเจน ช่องทางสามารถสตรีมตัวอย่างสด (`channels..streaming`) ได้โดยไม่ต้องมีคำตอบแบบบล็อก -ตัวเตือนตำแหน่ง config: ค่าเริ่มต้น `blockStreaming*` อยู่ใต้ -`agents.defaults` ไม่ใช่ config ราก +เตือนตำแหน่งการกำหนดค่า: ค่าเริ่มต้น `blockStreaming*` อยู่ภายใต้ +`agents.defaults` ไม่ใช่การกำหนดค่าราก -## โหมดสตรีมมิงแบบพรีวิว +## โหมดการสตรีมตัวอย่าง คีย์มาตรฐาน: `channels..streaming` โหมด: -- `off`: ปิดสตรีมมิงแบบพรีวิว -- `partial`: พรีวิวเดียวที่ถูกแทนที่ด้วยข้อความล่าสุด -- `block`: พรีวิวอัปเดตแบบแบ่งชังก์/ต่อท้ายเป็นขั้น ๆ -- `progress`: พรีวิวความคืบหน้า/สถานะระหว่างสร้าง และคำตอบสุดท้ายเมื่อเสร็จ +- `off`: ปิดใช้การสตรีมตัวอย่าง +- `partial`: ตัวอย่างเดียวที่ถูกแทนที่ด้วยข้อความล่าสุด +- `block`: อัปเดตตัวอย่างเป็นขั้นตอนแบบแบ่งชิ้น/ต่อท้าย +- `progress`: ตัวอย่างความคืบหน้า/สถานะระหว่างการสร้าง และคำตอบสุดท้ายเมื่อเสร็จสิ้น -`streaming.mode: "block"` เป็นโหมดสตรีมมิงแบบพรีวิวสำหรับช่องทางที่แก้ไขได้ -เช่น Discord และ Telegram โหมดนี้ไม่ได้เปิดการส่งแบบบล็อกของช่องทางที่นั่น -ใช้ `streaming.block.enabled` หรือคีย์ช่องทาง legacy `blockStreaming` เมื่อ -คุณต้องการการตอบกลับแบบบล็อกปกติ Microsoft Teams เป็นข้อยกเว้น: ไม่มี -draft-preview block transport ดังนั้น `streaming.mode: "block"` จึงแมปเป็นการส่งแบบบล็อกของ Teams -แทนสตรีมมิง partial/progress แบบ native +`streaming.mode: "block"` เป็นโหมดการสตรีมตัวอย่างสำหรับช่องทางที่แก้ไขได้ เช่น Discord และ Telegram ซึ่งไม่ได้เปิดใช้การส่งแบบบล็อกของช่องทางที่นั่น ใช้ `streaming.block.enabled` หรือคีย์ช่องทางเดิม `blockStreaming` เมื่อคุณต้องการคำตอบแบบบล็อกปกติ Microsoft Teams เป็นข้อยกเว้น: ไม่มีการขนส่งบล็อกแบบร่างตัวอย่าง ดังนั้น `streaming.mode: "block"` จึงแมปไปยังการส่งแบบบล็อกของ Teams แทนการสตรีมแบบบางส่วน/ความคืบหน้าเนทีฟ -### การแมประดับช่องทาง +### การแมปช่องทาง | ช่องทาง | `off` | `partial` | `block` | `progress` | | ---------- | ----- | --------- | ------- | ----------------------- | -| Telegram | ✅ | ✅ | ✅ | draft ความคืบหน้าที่แก้ไขได้ | -| Discord | ✅ | ✅ | ✅ | draft ความคืบหน้าที่แก้ไขได้ | +| Telegram | ✅ | ✅ | ✅ | ร่างความคืบหน้าที่แก้ไขได้ | +| Discord | ✅ | ✅ | ✅ | ร่างความคืบหน้าที่แก้ไขได้ | | Slack | ✅ | ✅ | ✅ | ✅ | | Mattermost | ✅ | ✅ | ✅ | ✅ | -| MS Teams | ✅ | ✅ | ✅ | สตรีมความคืบหน้าแบบ native | +| MS Teams | ✅ | ✅ | ✅ | สตรีมความคืบหน้าเนทีฟ | -เฉพาะ Slack: +สำหรับ Slack เท่านั้น: - `channels.slack.streaming.nativeTransport` สลับการเรียก Slack native streaming API เมื่อ `channels.slack.streaming.mode="partial"` (ค่าเริ่มต้น: `true`) -- Slack native streaming และสถานะเธรดผู้ช่วยของ Slack ต้องมีเป้าหมายเป็นเธรดตอบกลับ DMs ระดับบนสุดจะไม่แสดงพรีวิวแบบ thread-style นั้น แต่ยังใช้โพสต์พรีวิว draft ของ Slack และการแก้ไขได้ +- Slack native streaming และสถานะเธรดผู้ช่วยของ Slack ต้องมีเป้าหมายเธรดตอบกลับ DM ระดับบนสุดไม่แสดงตัวอย่างแบบเธรดนั้น แต่ยังสามารถใช้โพสต์และการแก้ไขตัวอย่างร่างของ Slack ได้ -การย้ายคีย์ legacy: +การย้ายคีย์เดิม: -- Telegram: ค่า legacy `streamMode` และค่า scalar/boolean `streaming` จะถูกตรวจพบและย้ายโดยเส้นทางความเข้ากันได้ของ doctor/config ไปยัง `streaming.mode` -- Discord: `streamMode` + boolean `streaming` ย้ายอัตโนมัติเป็น enum `streaming` -- Slack: `streamMode` ย้ายอัตโนมัติเป็น `streaming.mode`; boolean `streaming` ย้ายอัตโนมัติเป็น `streaming.mode` พร้อม `streaming.nativeTransport`; legacy `nativeStreaming` ย้ายอัตโนมัติเป็น `streaming.nativeTransport` +- Telegram: ค่าเดิม `streamMode` และค่า `streaming` แบบสเกลาร์/บูลีนจะถูกตรวจพบและย้ายโดยเส้นทางความเข้ากันได้ของ doctor/config ไปยัง `streaming.mode` +- Discord: `streamMode` + `streaming` แบบบูลีนจะย้ายอัตโนมัติไปยัง enum `streaming` +- Slack: `streamMode` จะย้ายอัตโนมัติไปยัง `streaming.mode`; `streaming` แบบบูลีนจะย้ายอัตโนมัติไปยัง `streaming.mode` พร้อม `streaming.nativeTransport`; `nativeStreaming` แบบเดิมจะย้ายอัตโนมัติไปยัง `streaming.nativeTransport` -### พฤติกรรมขณะรันไทม์ +### พฤติกรรมรันไทม์ Telegram: -- ใช้ `sendMessage` + `editMessageText` สำหรับอัปเดตพรีวิวใน DMs และกลุ่ม/หัวข้อ -- ส่งข้อความสุดท้ายใหม่แทนการแก้ไขข้อความเดิมเมื่อพรีวิวมองเห็นมาประมาณหนึ่งนาที จากนั้นล้างพรีวิวเพื่อให้ timestamp ของ Telegram สะท้อนเวลาที่ตอบเสร็จ -- ข้ามสตรีมมิงแบบพรีวิวเมื่อเปิดสตรีมมิงแบบบล็อกของ Telegram อย่างชัดเจน (เพื่อหลีกเลี่ยงการสตรีมซ้ำสองทาง) -- `/reasoning stream` สามารถเขียน reasoning ไปยังพรีวิวได้ +- ใช้การอัปเดตตัวอย่างด้วย `sendMessage` + `editMessageText` ทั้งใน DM และกลุ่ม/หัวข้อ +- ส่งข้อความสุดท้ายใหม่แทนการแก้ไขที่เดิมเมื่อมีตัวอย่างแสดงอยู่ประมาณหนึ่งนาที จากนั้นล้างตัวอย่างเพื่อให้เวลาประทับของ Telegram สะท้อนการตอบกลับเสร็จสิ้น +- ข้ามการสตรีมตัวอย่างเมื่อเปิดใช้การสตรีมแบบบล็อกของ Telegram อย่างชัดเจน (เพื่อหลีกเลี่ยงการสตรีมซ้ำซ้อน) +- `/reasoning stream` สามารถเขียนเหตุผลไปยังตัวอย่างชั่วคราวที่ถูกลบหลังการส่งสุดท้าย Discord: -- ใช้ข้อความพรีวิวแบบส่ง + แก้ไข -- โหมด `block` ใช้การแบ่งชังก์ draft (`draftChunk`) -- ข้ามสตรีมมิงแบบพรีวิวเมื่อเปิดสตรีมมิงแบบบล็อกของ Discord อย่างชัดเจน -- payload สื่อสุดท้าย ข้อผิดพลาด และ explicit-reply จะยกเลิกพรีวิวที่ค้างอยู่โดยไม่ flush draft ใหม่ แล้วใช้การส่งตามปกติ +- ใช้การส่ง + แก้ไขข้อความตัวอย่าง +- โหมด `block` ใช้การแบ่งชิ้นร่าง (`draftChunk`) +- ข้ามการสตรีมตัวอย่างเมื่อเปิดใช้การสตรีมแบบบล็อกของ Discord อย่างชัดเจน +- เพย์โหลดสื่อสุดท้าย ข้อผิดพลาด และการตอบกลับแบบชัดเจนจะยกเลิกตัวอย่างที่ค้างอยู่โดยไม่ล้างร่างใหม่ แล้วใช้การส่งปกติ Slack: - `partial` สามารถใช้ Slack native streaming (`chat.startStream`/`append`/`stop`) เมื่อพร้อมใช้งาน -- `block` ใช้พรีวิว draft แบบต่อท้าย -- `progress` ใช้ข้อความพรีวิวสถานะ แล้วตามด้วยคำตอบสุดท้าย -- DMs ระดับบนสุดที่ไม่มีเธรดตอบกลับใช้โพสต์พรีวิว draft และการแก้ไขแทน Slack native streaming -- Native และ draft preview streaming จะระงับการตอบกลับแบบบล็อกสำหรับเทิร์นนั้น ดังนั้นการตอบกลับของ Slack จึงถูกสตรีมผ่านเส้นทางการส่งเพียงเส้นทางเดียว -- payload สื่อ/ข้อผิดพลาดสุดท้ายและ progress finals จะไม่สร้างข้อความ draft ชั่วคราวที่ทิ้งได้; เฉพาะ text/block finals ที่แก้ไขพรีวิวได้เท่านั้นที่จะ flush ข้อความ draft ที่ค้างอยู่ +- `block` ใช้ตัวอย่างร่างแบบต่อท้าย +- `progress` ใช้ข้อความตัวอย่างสถานะ แล้วตามด้วยคำตอบสุดท้าย +- DM ระดับบนสุดที่ไม่มีเธรดตอบกลับจะใช้โพสต์และการแก้ไขตัวอย่างร่างแทน Slack native streaming +- การสตรีมตัวอย่างทั้งแบบเนทีฟและแบบร่างจะระงับคำตอบแบบบล็อกสำหรับเทิร์นนั้น ดังนั้นคำตอบของ Slack จะถูกสตรีมผ่านเส้นทางการส่งเพียงเส้นทางเดียว +- เพย์โหลดสื่อ/ข้อผิดพลาดสุดท้ายและผลลัพธ์สุดท้ายของความคืบหน้าจะไม่สร้างข้อความร่างชั่วคราว; เฉพาะผลลัพธ์สุดท้ายแบบข้อความ/บล็อกที่แก้ไขตัวอย่างได้เท่านั้นที่จะล้างข้อความร่างที่ค้างอยู่ Mattermost: -- สตรีมการคิด กิจกรรมเครื่องมือ และข้อความตอบกลับบางส่วนลงในโพสต์พรีวิว draft เดียวที่ finalize ในที่เดิมเมื่อส่งคำตอบสุดท้ายได้อย่างปลอดภัย -- fallback ไปส่งโพสต์สุดท้ายใหม่ถ้าโพสต์พรีวิวถูกลบหรือไม่พร้อมใช้งานในเวลา finalize -- payload สื่อ/ข้อผิดพลาดสุดท้ายจะยกเลิกการอัปเดตพรีวิวที่ค้างอยู่ก่อนการส่งปกติ แทนการ flush โพสต์พรีวิวชั่วคราว +- สตรีมการคิด กิจกรรมเครื่องมือ และข้อความตอบกลับบางส่วนเข้าไปในโพสต์ตัวอย่างร่างเดียว ซึ่งจะสรุปจบที่เดิมเมื่อคำตอบสุดท้ายปลอดภัยที่จะส่ง +- ถอยกลับไปส่งโพสต์สุดท้ายใหม่หากโพสต์ตัวอย่างถูกลบหรือไม่พร้อมใช้งานด้วยเหตุผลอื่นเมื่อถึงเวลาสรุปจบ +- เพย์โหลดสื่อ/ข้อผิดพลาดสุดท้ายจะยกเลิกการอัปเดตตัวอย่างที่ค้างอยู่ก่อนการส่งปกติ แทนที่จะล้างโพสต์ตัวอย่างชั่วคราว Matrix: -- พรีวิว draft finalize ในที่เดิมเมื่อข้อความสุดท้ายสามารถใช้ event พรีวิวซ้ำได้ -- finals ที่เป็นเฉพาะสื่อ ข้อผิดพลาด และเป้าหมายตอบกลับไม่ตรงกันจะยกเลิกการอัปเดตพรีวิวที่ค้างอยู่ก่อนการส่งปกติ; พรีวิวเก่าที่มองเห็นอยู่แล้วจะถูก redact +- ตัวอย่างร่างจะสรุปจบที่เดิมเมื่อข้อความสุดท้ายสามารถใช้เหตุการณ์ตัวอย่างซ้ำได้ +- ผลลัพธ์สุดท้ายแบบเฉพาะสื่อ ข้อผิดพลาด และเป้าหมายตอบกลับไม่ตรงกันจะยกเลิกการอัปเดตตัวอย่างที่ค้างอยู่ก่อนการส่งปกติ; ตัวอย่างเก่าที่มองเห็นอยู่แล้วจะถูกแก้ไขทับ -### การอัปเดตพรีวิวความคืบหน้าของเครื่องมือ +### การอัปเดตตัวอย่างความคืบหน้าของเครื่องมือ -สตรีมมิงแบบพรีวิวยังสามารถรวมการอัปเดต **tool-progress** ได้ด้วย เช่น บรรทัดสถานะสั้น ๆ อย่าง "กำลังค้นหาเว็บ", "กำลังอ่านไฟล์", หรือ "กำลังเรียกเครื่องมือ" ซึ่งปรากฏในข้อความพรีวิวเดียวกันระหว่างที่เครื่องมือกำลังทำงาน ก่อนคำตอบสุดท้าย วิธีนี้ทำให้เทิร์นที่มีเครื่องมือหลายขั้นตอนยังดูมีความเคลื่อนไหว แทนที่จะเงียบระหว่างพรีวิวการคิดครั้งแรกกับคำตอบสุดท้าย +การสตรีมตัวอย่างยังสามารถรวมการอัปเดต **ความคืบหน้าของเครื่องมือ** ได้ด้วย ซึ่งเป็นบรรทัดสถานะสั้น ๆ เช่น "กำลังค้นหาเว็บ", "กำลังอ่านไฟล์" หรือ "กำลังเรียกเครื่องมือ" ที่ปรากฏในข้อความตัวอย่างเดียวกันขณะเครื่องมือกำลังทำงาน ก่อนคำตอบสุดท้าย สิ่งนี้ทำให้เทิร์นเครื่องมือหลายขั้นตอนยังดูมีการเคลื่อนไหว แทนที่จะเงียบระหว่างตัวอย่างการคิดแรกกับคำตอบสุดท้าย พื้นผิวที่รองรับ: -- **Discord**, **Slack**, **Telegram**, และ **Matrix** สตรีม tool-progress ลงในการแก้ไขพรีวิวสดตามค่าเริ่มต้นเมื่อสตรีมมิงแบบพรีวิวทำงาน Microsoft Teams ใช้สตรีมความคืบหน้าแบบ native ในแชตส่วนตัว -- Telegram ได้เผยแพร่พร้อมการอัปเดตพรีวิว tool-progress ที่เปิดใช้งานตั้งแต่ `v2026.4.22`; การเปิดไว้ต่อไปจะรักษาพฤติกรรมที่ปล่อยแล้วนั้น -- **Mattermost** รวมกิจกรรมเครื่องมือเข้าในโพสต์พรีวิว draft เดียวอยู่แล้ว (ดูด้านบน) -- การแก้ไข tool-progress จะตามโหมดสตรีมมิงแบบพรีวิวที่ใช้งานอยู่; จะถูกข้ามเมื่อสตรีมมิงแบบพรีวิวเป็น `off` หรือเมื่อสตรีมมิงแบบบล็อกเข้าควบคุมข้อความแล้ว บน Telegram, `streaming.mode: "off"` คือ final-only: ข้อความความคืบหน้าทั่วไปจะถูกระงับด้วยแทนที่จะถูกส่งเป็นข้อความสถานะแยกต่างหาก ในขณะที่ approval prompts, payload สื่อ และข้อผิดพลาดยัง route ตามปกติ -- หากต้องการคงสตรีมมิงแบบพรีวิวไว้แต่ซ่อนบรรทัด tool-progress ให้ตั้ง `streaming.preview.toolProgress` เป็น `false` สำหรับช่องทางนั้น หากต้องการปิดการแก้ไขพรีวิวทั้งหมด ให้ตั้ง `streaming.mode` เป็น `off` -- การตอบกลับ quote ที่เลือกใน Telegram เป็นข้อยกเว้น: เมื่อ `replyToMode` ไม่ใช่ `"off"` และมีข้อความ quote ที่เลือก OpenClaw จะข้ามสตรีมพรีวิวคำตอบสำหรับเทิร์นนั้น ดังนั้นบรรทัดพรีวิว tool-progress จึงไม่สามารถเรนเดอร์ได้ การตอบกลับข้อความปัจจุบันที่ไม่มีข้อความ quote ที่เลือกยังคงใช้สตรีมมิงแบบพรีวิว ดูรายละเอียดใน [เอกสารช่องทาง Telegram](/th/channels/telegram) +- **Discord**, **Slack**, **Telegram** และ **Matrix** สตรีมความคืบหน้าของเครื่องมือเข้าไปในการแก้ไขตัวอย่างสดโดยค่าเริ่มต้นเมื่อการสตรีมตัวอย่างทำงานอยู่ Microsoft Teams ใช้สตรีมความคืบหน้าเนทีฟในแชตส่วนตัว +- Telegram ส่งมาพร้อมการเปิดใช้การอัปเดตตัวอย่างความคืบหน้าของเครื่องมือตั้งแต่ `v2026.4.22`; การเปิดไว้ต่อไปจะรักษาพฤติกรรมที่เผยแพร่แล้วนั้น +- **Mattermost** รวมกิจกรรมเครื่องมือเข้าไปในโพสต์ตัวอย่างร่างเดียวอยู่แล้ว (ดูด้านบน) +- การแก้ไขความคืบหน้าของเครื่องมือจะทำตามโหมดการสตรีมตัวอย่างที่ใช้งานอยู่; จะถูกข้ามเมื่อการสตรีมตัวอย่างเป็น `off` หรือเมื่อการสตรีมแบบบล็อกเข้าควบคุมข้อความแล้ว บน Telegram, `streaming.mode: "off"` คือเฉพาะคำตอบสุดท้าย: ข้อความคืบหน้าทั่วไปจะถูกระงับด้วย แทนที่จะถูกส่งเป็นข้อความสถานะแยกต่างหาก ขณะที่พรอมป์อนุมัติ เพย์โหลดสื่อ และข้อผิดพลาดยังคงถูกส่งตามปกติ +- หากต้องการคงการสตรีมตัวอย่างไว้แต่ซ่อนบรรทัดความคืบหน้าของเครื่องมือ ให้ตั้งค่า `streaming.preview.toolProgress` เป็น `false` สำหรับช่องทางนั้น หากต้องการให้บรรทัดความคืบหน้าของเครื่องมือยังมองเห็นได้ขณะซ่อนข้อความคำสั่ง/การดำเนินการ ให้ตั้งค่า `streaming.preview.commandText` เป็น `"status"` หรือ `streaming.progress.commandText` เป็น `"status"`; ค่าเริ่มต้นคือ `"raw"` เพื่อรักษาพฤติกรรมที่เผยแพร่แล้ว นโยบายนี้ใช้ร่วมกันโดยช่องทางแบบร่าง/ความคืบหน้าที่ใช้ตัวแสดงผลความคืบหน้าแบบกะทัดรัดของ OpenClaw รวมถึง Discord, Matrix, Microsoft Teams, Mattermost, ตัวอย่างร่างของ Slack และ Telegram หากต้องการปิดการแก้ไขตัวอย่างทั้งหมด ให้ตั้งค่า `streaming.mode` เป็น `off` +- การตอบกลับด้วยข้อความอ้างอิงที่เลือกใน Telegram เป็นข้อยกเว้น: เมื่อ `replyToMode` ไม่ใช่ `"off"` และมีข้อความอ้างอิงที่เลือกอยู่ OpenClaw จะข้ามสตรีมตัวอย่างคำตอบสำหรับเทิร์นนั้น ดังนั้นบรรทัดตัวอย่างความคืบหน้าของเครื่องมือจึงไม่สามารถแสดงผลได้ การตอบกลับข้อความปัจจุบันที่ไม่มีข้อความอ้างอิงที่เลือกยังคงใช้การสตรีมตัวอย่าง ดูรายละเอียดใน [เอกสารช่องทาง Telegram](/th/channels/telegram) -ตัวอย่าง: +ให้บรรทัดความคืบหน้ายังคงมองเห็นได้ แต่ซ่อนข้อความ command/exec ดิบ: ```json { @@ -220,7 +202,26 @@ Matrix: "streaming": { "mode": "partial", "preview": { - "toolProgress": false + "toolProgress": true, + "commandText": "status" + } + } + } + } +} +``` + +ใช้โครงสร้างเดียวกันภายใต้คีย์ช่องทางความคืบหน้าแบบกะทัดรัดอื่น เช่น `channels.discord`, `channels.matrix`, `channels.msteams`, `channels.mattermost` หรือการแสดงตัวอย่างร่างของ Slack สำหรับโหมดร่างความคืบหน้า ให้ใส่นโยบายเดียวกันภายใต้ `streaming.progress`: + +```json +{ + "channels": { + "telegram": { + "streaming": { + "mode": "progress", + "progress": { + "toolProgress": true, + "commandText": "status" } } } @@ -230,7 +231,7 @@ Matrix: ## ที่เกี่ยวข้อง -- [Progress drafts](/th/concepts/progress-drafts) — ข้อความงานที่กำลังดำเนินอยู่ซึ่งมองเห็นได้และอัปเดตระหว่างเทิร์นที่ยาว +- [ร่างความคืบหน้า](/th/concepts/progress-drafts) — ข้อความงานที่กำลังดำเนินการซึ่งมองเห็นได้และอัปเดตระหว่างเทิร์นที่ใช้เวลานาน - [ข้อความ](/th/concepts/messages) — วงจรชีวิตและการส่งข้อความ - [ลองใหม่](/th/concepts/retry) — พฤติกรรมการลองใหม่เมื่อการส่งล้มเหลว -- [ช่องทาง](/th/channels) — การรองรับสตรีมมิงต่อช่องทาง +- [ช่องทาง](/th/channels) — การรองรับการสตรีมแยกตามช่องทาง diff --git a/docs/th/help/testing.md b/docs/th/help/testing.md index 812ea7401..589934067 100644 --- a/docs/th/help/testing.md +++ b/docs/th/help/testing.md @@ -1,34 +1,34 @@ --- read_when: - - การรันการทดสอบในเครื่องหรือใน CI - - การเพิ่มการทดสอบถดถอยสำหรับบั๊กของโมเดล/ผู้ให้บริการ + - การเรียกใช้การทดสอบในเครื่องหรือใน CI + - การเพิ่มการทดสอบรีเกรสชันสำหรับข้อบกพร่องของโมเดล/ผู้ให้บริการ - การดีบักพฤติกรรมของ Gateway + เอเจนต์ -summary: 'ชุดเครื่องมือทดสอบ: ชุดทดสอบ unit/e2e/live, ตัวรัน Docker และสิ่งที่การทดสอบแต่ละรายการครอบคลุม' +summary: 'ชุดเครื่องมือทดสอบ: ชุดทดสอบ unit/e2e/live, รันเนอร์ Docker และสิ่งที่การทดสอบแต่ละรายการครอบคลุม' title: การทดสอบ x-i18n: - generated_at: "2026-05-03T10:12:58Z" + generated_at: "2026-05-04T07:05:12Z" model: gpt-5.5 provider: openai - source_hash: e7fb57bee958c4e6243f02193a657d7b19ca633c7a27f70eac6b590931390671 + source_hash: ad724e3879d1d4dec21c4ea97e2fd5724c47269c1084c558a09f51bd72afc6a4 source_path: help/testing.md workflow: 16 --- -OpenClaw มีชุดทดสอบ Vitest สามชุด (หน่วย/การผสานรวม, e2e, live) และชุดตัวรัน Docker ขนาดเล็ก เอกสารนี้เป็นคู่มือ "วิธีที่เราทดสอบ": +OpenClaw มีชุดทดสอบ Vitest สามชุด (unit/integration, e2e, live) และชุด Docker runners ขนาดเล็ก เอกสารนี้เป็นคู่มือ "วิธีที่เราทดสอบ": -- แต่ละชุดทดสอบครอบคลุมอะไร (และตั้งใจ _ไม่_ ครอบคลุมอะไร) -- คำสั่งที่ควรรันสำหรับเวิร์กโฟลว์ทั่วไป (ในเครื่อง, ก่อน push, การดีบัก) -- วิธีที่การทดสอบ live ค้นหาข้อมูลรับรองและเลือกโมเดล/ผู้ให้บริการ -- วิธีเพิ่มการทดสอบถดถอยสำหรับปัญหาโมเดล/ผู้ให้บริการในโลกจริง +- แต่ละชุดครอบคลุมอะไรบ้าง (และอะไรที่ตั้งใจ _ไม่_ ครอบคลุม) +- ควรรันคำสั่งใดสำหรับเวิร์กโฟลว์ทั่วไป (ภายในเครื่อง, ก่อน push, การดีบัก) +- live tests ค้นพบข้อมูลรับรองและเลือกโมเดล/ผู้ให้บริการอย่างไร +- วิธีเพิ่ม regression สำหรับปัญหาโมเดล/ผู้ให้บริการจริง -**สแต็ก QA (qa-lab, qa-channel, เลนขนส่ง live)** มีเอกสารแยกต่างหาก: +**สแต็ก QA (qa-lab, qa-channel, live transport lanes)** มีเอกสารแยกต่างหาก: -- [ภาพรวม QA](/th/concepts/qa-e2e-automation) — สถาปัตยกรรม, พื้นผิวคำสั่ง, การเขียนสถานการณ์ -- [Matrix QA](/th/concepts/qa-matrix) — เอกสารอ้างอิงสำหรับ `pnpm openclaw qa matrix` -- [ช่องทาง QA](/th/channels/qa-channel) — Plugin ขนส่งสังเคราะห์ที่ใช้โดยสถานการณ์ที่อิงกับ repo +- [ภาพรวม QA](/th/concepts/qa-e2e-automation) — สถาปัตยกรรม, command surface, การเขียน scenario +- [Matrix QA](/th/concepts/qa-matrix) — ข้อมูลอ้างอิงสำหรับ `pnpm openclaw qa matrix` +- [QA channel](/th/channels/qa-channel) — synthetic transport plugin ที่ใช้โดย scenario ที่อ้างอิง repo -หน้านี้ครอบคลุมการรันชุดทดสอบปกติและตัวรัน Docker/Parallels ส่วนตัวรันเฉพาะ QA ด้านล่าง ([ตัวรันเฉพาะ QA](#qa-specific-runners)) แสดงคำสั่ง `qa` ที่เป็นรูปธรรมและชี้กลับไปยังเอกสารอ้างอิงด้านบน +หน้านี้ครอบคลุมการรันชุดทดสอบปกติและ Docker/Parallels runners ส่วน QA-specific runners ด้านล่าง ([QA-specific runners](#qa-specific-runners)) แสดงรายการการเรียกใช้ `qa` ที่เป็นรูปธรรมและชี้กลับไปยังเอกสารอ้างอิงด้านบน ## เริ่มต้นอย่างรวดเร็ว @@ -36,180 +36,157 @@ OpenClaw มีชุดทดสอบ Vitest สามชุด (หน่ว ในวันส่วนใหญ่: - เกตเต็มรูปแบบ (คาดหวังก่อน push): `pnpm build && pnpm check && pnpm check:test-types && pnpm test` -- การรันชุดทดสอบเต็มในเครื่องที่เร็วขึ้นบนเครื่องที่มีทรัพยากรมาก: `pnpm test:max` -- ลูปเฝ้าดู Vitest โดยตรง: `pnpm test:watch` -- การระบุไฟล์โดยตรงตอนนี้กำหนดเส้นทาง extension/channel ด้วย: `pnpm test extensions/discord/src/monitor/message-handler.preflight.test.ts` -- ควรใช้การรันแบบเจาะจงก่อนเมื่อคุณกำลังวนแก้ความล้มเหลวเดียว -- ไซต์ QA ที่รองรับด้วย Docker: `pnpm qa:lab:up` -- เลน QA ที่รองรับด้วย VM Linux: `pnpm openclaw qa suite --runner multipass --scenario channel-chat-baseline` +- การรัน full-suite ภายในเครื่องที่เร็วขึ้นบนเครื่องที่มีทรัพยากรพอ: `pnpm test:max` +- วงจร Vitest watch โดยตรง: `pnpm test:watch` +- การเจาะจงไฟล์โดยตรงตอนนี้ route เส้นทาง extension/channel ด้วย: `pnpm test extensions/discord/src/monitor/message-handler.preflight.test.ts` +- ควรใช้ targeted runs ก่อนเมื่อคุณกำลังวนแก้ failure เดียว +- ไซต์ QA ที่อิง Docker: `pnpm qa:lab:up` +- QA lane ที่อิง Linux VM: `pnpm openclaw qa suite --runner multipass --scenario channel-chat-baseline` -เมื่อคุณแตะการทดสอบหรือต้องการความมั่นใจเพิ่ม: +เมื่อคุณแตะ tests หรือต้องการความมั่นใจเพิ่มเติม: -- เกตความครอบคลุม: `pnpm test:coverage` -- ชุดทดสอบ E2E: `pnpm test:e2e` +- เกต coverage: `pnpm test:coverage` +- ชุด E2E: `pnpm test:e2e` -เมื่อดีบักผู้ให้บริการ/โมเดลจริง (ต้องมีข้อมูลรับรองจริง): +เมื่อดีบักผู้ให้บริการ/โมเดลจริง (ต้องใช้ creds จริง): -- ชุดทดสอบ live (โมเดล + การตรวจสอบ Gateway tool/image): `pnpm test:live` -- เจาะจงไฟล์ live หนึ่งไฟล์แบบเงียบ: `pnpm test:live -- src/agents/models.profiles.live.test.ts` -- รายงานประสิทธิภาพรันไทม์: dispatch `OpenClaw Performance` ด้วย - `live_gpt54=true` สำหรับเทิร์น agent `openai/gpt-5.4` จริง หรือ - `deep_profile=true` สำหรับอาร์ติแฟกต์ CPU/heap/trace ของ Kova การรันตามกำหนดรายวัน - เผยแพร่อาร์ติแฟกต์เลน mock-provider, deep-profile และ GPT 5.4 ไปยัง - `openclaw/clawgrit-reports` เมื่อกำหนดค่า `CLAWGRIT_REPORTS_TOKEN` แล้ว - รายงาน mock-provider ยังรวมตัวเลขการบูต Gateway ระดับซอร์ส, หน่วยความจำ, - plugin-pressure, fake-model hello-loop ซ้ำ และการเริ่มต้น CLI ด้วย -- การกวาดโมเดล live ด้วย Docker: `pnpm test:docker:live-models` - - แต่ละโมเดลที่เลือกตอนนี้รันเทิร์นข้อความและโพรบขนาดเล็กแบบอ่านไฟล์ - โมเดลที่ metadata ระบุว่ารับอินพุต `image` จะรันเทิร์นรูปภาพขนาดจิ๋วด้วย - ปิดโพรบเพิ่มเติมด้วย `OPENCLAW_LIVE_MODEL_FILE_PROBE=0` หรือ - `OPENCLAW_LIVE_MODEL_IMAGE_PROBE=0` เมื่อแยกปัญหาผู้ให้บริการ - - ความครอบคลุมใน CI: `OpenClaw Scheduled Live And E2E Checks` รายวันและ - `OpenClaw Release Checks` แบบ manual ต่างเรียกเวิร์กโฟลว์ live/E2E ที่นำกลับใช้ซ้ำได้ด้วย - `include_live_suites: true` ซึ่งรวมงานเมทริกซ์โมเดล live ของ Docker แยกต่างหาก - ที่ shard ตามผู้ให้บริการ - - สำหรับการรันซ้ำ CI แบบเจาะจง ให้ dispatch `OpenClaw Live And E2E Checks (Reusable)` +- ชุด live (models + gateway tool/image probes): `pnpm test:live` +- เจาะจง live file เดียวแบบเงียบ: `pnpm test:live -- src/agents/models.profiles.live.test.ts` +- รายงาน runtime performance: dispatch `OpenClaw Performance` พร้อม + `live_gpt54=true` สำหรับ agent turn จริงของ `openai/gpt-5.4` หรือ + `deep_profile=true` สำหรับ artifact CPU/heap/trace ของ Kova การรันรายวันตามกำหนดเวลา + เผยแพร่ artifact ของ mock-provider, deep-profile, และ GPT 5.4 lane ไปยัง + `openclaw/clawgrit-reports` เมื่อกำหนดค่า `CLAWGRIT_REPORTS_TOKEN` แล้ว รายงาน + mock-provider ยังรวมตัวเลขระดับ source สำหรับ gateway boot, memory, + plugin-pressure, fake-model hello-loop ซ้ำ, และ CLI startup ด้วย +- Docker live model sweep: `pnpm test:docker:live-models` + - โมเดลที่เลือกแต่ละตัวตอนนี้รัน text turn พร้อม probe ขนาดเล็กแบบ file-read-style + โมเดลที่ metadata ประกาศอินพุต `image` จะรัน tiny image turn ด้วย + ปิด probe เพิ่มเติมด้วย `OPENCLAW_LIVE_MODEL_FILE_PROBE=0` หรือ + `OPENCLAW_LIVE_MODEL_IMAGE_PROBE=0` เมื่อแยกตรวจ failure ของผู้ให้บริการ + - coverage ใน CI: `OpenClaw Scheduled Live And E2E Checks` รายวันและ + `OpenClaw Release Checks` แบบ manual ต่างเรียก reusable live/E2E workflow ด้วย + `include_live_suites: true` ซึ่งรวม Docker live model matrix jobs แยกตามผู้ให้บริการ + - สำหรับการ rerun ใน CI แบบเจาะจง ให้ dispatch `OpenClaw Live And E2E Checks (Reusable)` ด้วย `include_live_suites: true` และ `live_models_only: true` - - เพิ่ม secret ผู้ให้บริการที่มีสัญญาณสูงใหม่ใน `scripts/ci-hydrate-live-auth.sh` + - เพิ่ม provider secrets ที่มี signal สูงใหม่ลงใน `scripts/ci-hydrate-live-auth.sh` รวมถึง `.github/workflows/openclaw-live-and-e2e-checks-reusable.yml` และ caller - แบบ scheduled/release ของมัน -- smoke สำหรับแชตที่ bind กับ Codex native: `pnpm test:docker:live-codex-bind` - - รันเลน Docker live กับพาธ app-server ของ Codex, bind Slack DM สังเคราะห์ด้วย `/codex bind`, - ทดสอบ `/codex fast` และ - `/codex permissions` จากนั้นตรวจสอบการตอบกลับธรรมดาและเส้นทางไฟล์แนบรูปภาพ - ผ่านการ binding Plugin แบบ native แทน ACP -- smoke สำหรับ harness app-server ของ Codex: `pnpm test:docker:live-codex-harness` - - รันเทิร์น agent ของ Gateway ผ่าน harness app-server ของ Codex ที่ Plugin เป็นเจ้าของ - ตรวจสอบ `/codex status` และ `/codex models` และโดยค่าเริ่มต้นทดสอบโพรบรูปภาพ, - Cron MCP, sub-agent และ Guardian ปิดโพรบ sub-agent ด้วย - `OPENCLAW_LIVE_CODEX_HARNESS_SUBAGENT_PROBE=0` เมื่อแยกความล้มเหลวอื่นของ - app-server Codex สำหรับการตรวจ sub-agent แบบเจาะจง ให้ปิดโพรบอื่น: - `OPENCLAW_LIVE_CODEX_HARNESS_IMAGE_PROBE=0 OPENCLAW_LIVE_CODEX_HARNESS_MCP_PROBE=0 OPENCLAW_LIVE_CODEX_HARNESS_GUARDIAN_PROBE=0 OPENCLAW_LIVE_CODEX_HARNESS_SUBAGENT_PROBE=1 pnpm test:docker:live-codex-harness` - คำสั่งนี้จะออกหลังโพรบ sub-agent เว้นแต่ตั้งค่า + แบบ scheduled/release ของไฟล์นั้น +- Native Codex bound-chat smoke: `pnpm test:docker:live-codex-bind` + - รัน Docker live lane กับเส้นทาง Codex app-server, bind synthetic + Slack DM ด้วย `/codex bind`, ทดสอบ `/codex fast` และ + `/codex permissions`, จากนั้นตรวจสอบ plain reply และ image attachment + route ผ่าน native plugin binding แทน ACP +- Codex app-server harness smoke: `pnpm test:docker:live-codex-harness` + - รัน gateway agent turns ผ่าน Codex app-server harness ที่ Plugin เป็นเจ้าของ, + ตรวจสอบ `/codex status` และ `/codex models`, และโดยค่าเริ่มต้นจะทดสอบ image, + cron MCP, sub-agent, และ Guardian probes ปิด sub-agent probe ด้วย + `OPENCLAW_LIVE_CODEX_HARNESS_SUBAGENT_PROBE=0` เมื่อแยกตรวจ failure อื่นของ Codex + app-server สำหรับการตรวจ sub-agent แบบเจาะจง ให้ปิด probe อื่น: + `OPENCLAW_LIVE_CODEX_HARNESS_IMAGE_PROBE=0 OPENCLAW_LIVE_CODEX_HARNESS_MCP_PROBE=0 OPENCLAW_LIVE_CODEX_HARNESS_GUARDIAN_PROBE=0 OPENCLAW_LIVE_CODEX_HARNESS_SUBAGENT_PROBE=1 pnpm test:docker:live-codex-harness`. + คำสั่งนี้จะออกหลังจาก sub-agent probe เว้นแต่จะตั้งค่า `OPENCLAW_LIVE_CODEX_HARNESS_SUBAGENT_ONLY=0` -- smoke คำสั่งกู้คืน Crestodian: `pnpm test:live:crestodian-rescue-channel` - - การตรวจแบบสมัครใจที่รัดกุมเป็นพิเศษสำหรับพื้นผิวคำสั่งกู้คืน message-channel - โดยจะทดสอบ `/crestodian status`, จัดคิวการเปลี่ยนโมเดลแบบถาวร, - ตอบกลับ `/crestodian yes` และตรวจสอบพาธการเขียน audit/config -- smoke Docker สำหรับ planner ของ Crestodian: `pnpm test:docker:crestodian-planner` - - รัน Crestodian ในคอนเทนเนอร์ที่ไม่มีคอนฟิกพร้อม Claude CLI ปลอมบน `PATH` - และตรวจสอบว่า fallback planner แบบ fuzzy แปลเป็นการเขียนคอนฟิกแบบ typed ที่มี audit -- smoke Docker สำหรับการรันครั้งแรกของ Crestodian: `pnpm test:docker:crestodian-first-run` - - เริ่มจากไดเรกทอรีสถานะ OpenClaw ว่าง, กำหนดเส้นทาง `openclaw` เปล่าไปยัง - Crestodian, ใช้การเขียน setup/model/agent/Discord Plugin + SecretRef, - ตรวจสอบคอนฟิก และตรวจสอบรายการ audit พาธตั้งค่า Ring 0 เดียวกันยังครอบคลุมใน QA Lab โดย +- Crestodian rescue command smoke: `pnpm test:live:crestodian-rescue-channel` + - การตรวจแบบ opt-in belt-and-suspenders สำหรับพื้นผิวคำสั่ง rescue ของ message-channel + โดยทดสอบ `/crestodian status`, จัดคิวการเปลี่ยนโมเดลแบบ persistent, + ตอบกลับ `/crestodian yes`, และตรวจสอบเส้นทางการเขียน audit/config +- Crestodian planner Docker smoke: `pnpm test:docker:crestodian-planner` + - รัน Crestodian ใน container ที่ไม่มี config พร้อม fake Claude CLI บน `PATH` + และตรวจสอบว่า fuzzy planner fallback แปลเป็นการเขียน config แบบ typed ที่มี audit +- Crestodian first-run Docker smoke: `pnpm test:docker:crestodian-first-run` + - เริ่มจากไดเรกทอรีสถานะ OpenClaw ที่ว่างเปล่า, route `openclaw` เปล่าไปยัง + Crestodian, ใช้ setup/model/agent/Discord plugin + SecretRef writes, + ตรวจสอบ config, และตรวจสอบ audit entries เส้นทางตั้งค่า Ring 0 เดียวกันนี้ + ยังครอบคลุมใน QA Lab ด้วย `pnpm openclaw qa suite --scenario crestodian-ring-zero-setup` -- smoke ต้นทุน Moonshot/Kimi: เมื่อตั้งค่า `MOONSHOT_API_KEY` แล้ว ให้รัน - `openclaw models list --provider moonshot --json` จากนั้นรัน +- Moonshot/Kimi cost smoke: เมื่อตั้งค่า `MOONSHOT_API_KEY` แล้ว ให้รัน + `openclaw models list --provider moonshot --json`, จากนั้นรัน `openclaw agent --local --session-id live-kimi-cost --message 'Reply exactly: KIMI_LIVE_OK' --thinking off --json` - แบบแยกกับ `moonshot/kimi-k2.6` ตรวจสอบว่า JSON รายงาน Moonshot/K2.6 และ - transcript ของ assistant เก็บ `usage.cost` ที่ normalized แล้ว + แบบ isolated กับ `moonshot/kimi-k2.6` ตรวจสอบว่า JSON รายงาน Moonshot/K2.6 และ + transcript ของ assistant เก็บ `usage.cost` ที่ normalize แล้ว -เมื่อคุณต้องการเฉพาะกรณีที่ล้มเหลวหนึ่งกรณี ควรจำกัดขอบเขตการทดสอบ live ผ่านตัวแปร env allowlist ที่อธิบายด้านล่าง +เมื่อคุณต้องการ failure case เดียวเท่านั้น ควรจำกัด live tests ให้แคบลงด้วย allowlist env vars ที่อธิบายไว้ด้านล่าง -## ตัวรันเฉพาะ QA +## QA-specific runners คำสั่งเหล่านี้อยู่ข้างชุดทดสอบหลักเมื่อคุณต้องการความสมจริงแบบ QA-lab: -CI รัน QA Lab ในเวิร์กโฟลว์เฉพาะ Agentic parity ซ้อนอยู่ภายใต้ -`QA-Lab - All Lanes` และการตรวจสอบ release ไม่ใช่เวิร์กโฟลว์ PR แยกต่างหาก -การตรวจสอบแบบกว้างควรใช้ `Full Release Validation` ด้วย +CI รัน QA Lab ใน workflow เฉพาะ Agentic parity ซ้อนอยู่ใต้ +`QA-Lab - All Lanes` และ release validation ไม่ใช่ PR workflow แบบ standalone +การตรวจสอบแบบกว้างควรใช้ `Full Release Validation` พร้อม `rerun_group=qa-parity` หรือกลุ่ม QA ของ release-checks `QA-Lab - All Lanes` -รันทุกคืนบน `main` และจาก manual dispatch พร้อมเลน mock parity, เลน Matrix live, -เลน Telegram live ที่ Convex จัดการ และเลน Discord live ที่ Convex จัดการ -เป็นงานแบบขนาน Scheduled QA และ release checks ส่ง Matrix -`--profile fast` อย่างชัดเจน ขณะที่ค่าเริ่มต้นของ Matrix CLI และ input เวิร์กโฟลว์แบบ manual -ยังคงเป็น `all`; manual dispatch สามารถ shard `all` เป็นงาน `transport`, -`media`, `e2ee-smoke`, `e2ee-deep` และ `e2ee-cli` ได้ `OpenClaw Release -Checks` รัน parity รวมถึงเลน Matrix และ Telegram แบบ fast ก่อนอนุมัติ release -โดยใช้ `mock-openai/gpt-5.5` สำหรับการตรวจ release transport เพื่อให้ผลคงที่ -และหลีกเลี่ยงการเริ่มต้น provider-plugin ตามปกติ Gateway ขนส่ง live เหล่านี้ -ปิดการค้นหาหน่วยความจำไว้; พฤติกรรมหน่วยความจำยังครอบคลุมโดยชุด QA parity +รันทุกคืนบน `main` และจาก manual dispatch พร้อม mock parity lane, live +Matrix lane, Convex-managed live Telegram lane, และ Convex-managed live Discord +lane เป็นงานขนาน Scheduled QA และ release checks ส่ง Matrix +`--profile fast` อย่างชัดเจน ขณะที่ค่าเริ่มต้นของ Matrix CLI และ manual workflow input +ยังเป็น `all`; manual dispatch สามารถ shard `all` เป็นงาน `transport`, +`media`, `e2ee-smoke`, `e2ee-deep`, และ `e2ee-cli` ได้ `OpenClaw Release +Checks` รัน parity รวมถึง fast Matrix และ Telegram lanes ก่อนอนุมัติ release +โดยใช้ `mock-openai/gpt-5.5` สำหรับ release transport checks เพื่อให้ deterministic +และหลีกเลี่ยงการ startup ปกติของ provider-plugin live transport gateways เหล่านี้ +ปิด memory search; พฤติกรรม memory ยังคงครอบคลุมโดยชุด QA parity -shard สื่อ live สำหรับ full release ใช้ +full release live media shards ใช้ `ghcr.io/openclaw/openclaw-live-media-runner:ubuntu-24.04` ซึ่งมี -`ffmpeg` และ `ffprobe` อยู่แล้ว shard โมเดล/แบ็กเอนด์ live ของ Docker ใช้อิมเมจร่วม -`ghcr.io/openclaw/openclaw-live-test:` ที่ build หนึ่งครั้งต่อ commit ที่เลือก -จากนั้น pull ด้วย `OPENCLAW_SKIP_DOCKER_BUILD=1` แทนการ rebuild +`ffmpeg` และ `ffprobe` อยู่แล้ว Docker live model/backend shards ใช้อิมเมจร่วม +`ghcr.io/openclaw/openclaw-live-test:` ที่ build ครั้งเดียวต่อ commit +ที่เลือก แล้วจึง pull ด้วย `OPENCLAW_SKIP_DOCKER_BUILD=1` แทนการ rebuild ภายในทุก shard - `pnpm openclaw qa suite` - - เรียกใช้สถานการณ์ QA ที่อิงกับ repo โดยตรงบนโฮสต์ - - เรียกใช้สถานการณ์ที่เลือกหลายรายการพร้อมกันตามค่าเริ่มต้นด้วย Gateway worker - ที่แยกกัน `qa-channel` ใช้ concurrency 4 เป็นค่าเริ่มต้น (จำกัดด้วยจำนวน - สถานการณ์ที่เลือก) ใช้ `--concurrency ` เพื่อปรับจำนวน worker - หรือ `--concurrency 1` สำหรับ lane แบบ serial เดิม - - ออกด้วยสถานะไม่เป็นศูนย์เมื่อสถานการณ์ใดล้มเหลว ใช้ `--allow-failures` เมื่อคุณ - ต้องการ artifact โดยไม่มี exit code ที่ล้มเหลว - - รองรับโหมด provider `live-frontier`, `mock-openai` และ `aimock` - `aimock` เริ่มเซิร์ฟเวอร์ provider ภายในเครื่องที่อิงกับ AIMock สำหรับ - fixture เชิงทดลองและความครอบคลุม protocol-mock โดยไม่แทนที่ lane - `mock-openai` ที่รับรู้สถานการณ์ + - รันสถานการณ์ QA ที่อ้างอิงรีโปโดยตรงบนโฮสต์ + - รันสถานการณ์ที่เลือกหลายรายการแบบขนานเป็นค่าเริ่มต้นด้วย Gateway worker ที่แยกกัน `qa-channel` ใช้ concurrency ค่าเริ่มต้นเป็น 4 (จำกัดตามจำนวนสถานการณ์ที่เลือก) ใช้ `--concurrency ` เพื่อปรับจำนวน worker หรือ `--concurrency 1` สำหรับเลนแบบอนุกรมเดิม + - ออกด้วยสถานะไม่ใช่ศูนย์เมื่อมีสถานการณ์ใดล้มเหลว ใช้ `--allow-failures` เมื่อคุณต้องการอาร์ติแฟกต์โดยไม่มีรหัสออกที่ล้มเหลว + - รองรับโหมดผู้ให้บริการ `live-frontier`, `mock-openai`, และ `aimock` `aimock` เริ่มเซิร์ฟเวอร์ผู้ให้บริการภายในเครื่องที่อ้างอิง AIMock สำหรับความครอบคลุมของ fixture เชิงทดลองและ protocol-mock โดยไม่แทนที่เลน `mock-openai` ที่รับรู้สถานการณ์ - `pnpm test:gateway:cpu-scenarios` - - เรียกใช้ bench การเริ่มต้น Gateway พร้อมชุดสถานการณ์ QA Lab แบบ mock ขนาดเล็ก - (`channel-chat-baseline`, `memory-failure-fallback`, - `gateway-restart-inflight-run`) และเขียนสรุปการสังเกต CPU แบบรวมไว้ใต้ - `.artifacts/gateway-cpu-scenarios/` - - ทำเครื่องหมายเฉพาะการสังเกต CPU ร้อนที่ต่อเนื่องตามค่าเริ่มต้น (`--cpu-core-warn` - พร้อม `--hot-wall-warn-ms`) ดังนั้น burst สั้นๆ ตอนเริ่มต้นจะถูกบันทึกเป็น metric - โดยไม่ดูเหมือน regression ที่ทำให้ Gateway ตรึง CPU นานหลายนาที - - ใช้ artifact `dist` ที่ build แล้ว; เรียกใช้ build ก่อนเมื่อ checkout ยังไม่มี - output runtime ที่สดใหม่ + - รันเบนช์มาร์กการเริ่มต้น Gateway พร้อมแพ็กสถานการณ์ QA Lab แบบจำลองขนาดเล็ก (`channel-chat-baseline`, `memory-failure-fallback`, `gateway-restart-inflight-run`) และเขียนสรุปการสังเกต CPU แบบรวมไว้ใต้ `.artifacts/gateway-cpu-scenarios/` + - ตั้งค่าสถานะเฉพาะการสังเกต CPU ร้อนที่ต่อเนื่องเป็นค่าเริ่มต้น (`--cpu-core-warn` พร้อม `--hot-wall-warn-ms`) ดังนั้นการพุ่งสั้น ๆ ตอนเริ่มต้นจะถูกบันทึกเป็นเมตริกโดยไม่ดูเหมือนการถดถอยที่ Gateway ใช้ CPU เต็มนานหลายนาที + - ใช้อาร์ติแฟกต์ `dist` ที่ build แล้ว ให้รัน build ก่อนเมื่อ checkout ยังไม่มีเอาต์พุตรันไทม์ที่ใหม่ - `pnpm openclaw qa suite --runner multipass` - - เรียกใช้ชุด QA เดียวกันภายใน Multipass Linux VM แบบใช้แล้วทิ้ง - - คงพฤติกรรมการเลือกสถานการณ์แบบเดียวกับ `qa suite` บนโฮสต์ - - ใช้ flag การเลือก provider/model เดียวกับ `qa suite` - - การรัน live จะส่งต่อ input การยืนยันตัวตน QA ที่รองรับและใช้งานได้จริงสำหรับ guest: - key ของ provider จาก env, path config provider live ของ QA และ `CODEX_HOME` + - รันชุด QA เดียวกันภายใน Multipass Linux VM แบบใช้แล้วทิ้ง + - คงพฤติกรรมการเลือกสถานการณ์เดียวกับ `qa suite` บนโฮสต์ + - ใช้แฟล็กการเลือกผู้ให้บริการ/โมเดลเดียวกับ `qa suite` + - การรันสดจะส่งต่ออินพุต auth ของ QA ที่รองรับและใช้งานได้จริงสำหรับ guest: + คีย์ผู้ให้บริการจาก env, พาธ config ผู้ให้บริการสดของ QA, และ `CODEX_HOME` เมื่อมีอยู่ - - output dir ต้องอยู่ใต้ repo root เพื่อให้ guest เขียนกลับผ่าน workspace ที่ mount ได้ - - เขียนรายงาน QA + สรุปตามปกติ พร้อม log ของ Multipass ไว้ใต้ + - ไดเรกทอรีเอาต์พุตต้องอยู่ใต้รูทของรีโปเพื่อให้ guest เขียนกลับผ่าน workspace ที่เมานต์ได้ + - เขียนรายงาน QA ปกติ + สรุป พร้อมล็อก Multipass ไว้ใต้ `.artifacts/qa-e2e/...` - `pnpm qa:lab:up` - - เริ่มไซต์ QA ที่อิงกับ Docker สำหรับงาน QA แบบ operator + - เริ่มไซต์ QA ที่อ้างอิง Docker สำหรับงาน QA แบบผู้ปฏิบัติงาน - `pnpm test:docker:npm-onboard-channel-agent` - - build npm tarball จาก checkout ปัจจุบัน ติดตั้งแบบ global ใน - Docker เรียกใช้ onboarding ของ OpenAI API-key แบบไม่โต้ตอบ กำหนดค่า Telegram - ตามค่าเริ่มต้น ตรวจสอบว่า runtime ของ Plugin ที่ package แล้วโหลดได้โดยไม่ต้อง - ซ่อม dependency ตอนเริ่มต้น เรียกใช้ doctor และเรียกใช้ agent turn ภายในเครื่องหนึ่งครั้งกับ - endpoint OpenAI ที่ mock - - ใช้ `OPENCLAW_NPM_ONBOARD_CHANNEL=discord` เพื่อเรียกใช้ lane packaged-install - เดียวกันกับ Discord + - สร้าง npm tarball จาก checkout ปัจจุบัน ติดตั้งแบบ global ใน Docker รันการ onboarding คีย์ OpenAI API แบบไม่โต้ตอบ ตั้งค่า Telegram เป็นค่าเริ่มต้น ตรวจสอบว่ารันไทม์ Plugin ที่แพ็กโหลดได้โดยไม่ต้องซ่อมแซม dependency ตอนเริ่มต้น รัน doctor และรันหนึ่ง agent turn ภายในเครื่องกับ endpoint OpenAI จำลอง + - ใช้ `OPENCLAW_NPM_ONBOARD_CHANNEL=discord` เพื่อรันเลน packaged-install เดียวกันกับ Discord - `pnpm test:docker:session-runtime-context` - - เรียกใช้ Docker smoke ของแอปที่ build แล้วแบบ deterministic สำหรับ transcript - runtime context แบบฝังตัว โดยตรวจสอบว่า runtime context ที่ซ่อนของ OpenClaw - ถูก persist เป็นข้อความ custom ที่ไม่แสดงผล แทนที่จะรั่วไปยัง user turn ที่มองเห็นได้ - จากนั้น seed JSONL ของ session ที่เสียซึ่งได้รับผลกระทบ และตรวจสอบว่า - `openclaw doctor --fix` เขียนใหม่ไปยัง active branch พร้อม backup + - รัน smoke ของ Docker สำหรับแอปที่ build แล้วแบบกำหนดแน่นอนสำหรับทรานสคริปต์ embedded runtime context ตรวจสอบว่า OpenClaw runtime context ที่ซ่อนอยู่ถูกคงอยู่เป็นข้อความ custom ที่ไม่แสดงผล แทนที่จะรั่วไปยัง user turn ที่มองเห็นได้ จากนั้น seed session JSONL ที่เสียซึ่งได้รับผลกระทบ และตรวจสอบว่า `openclaw doctor --fix` เขียนใหม่ไปยังสาขาที่ใช้งานพร้อมสำรองข้อมูล - `pnpm test:docker:npm-telegram-live` - - ติดตั้ง package candidate ของ OpenClaw ใน Docker เรียกใช้ onboarding - ของ installed-package กำหนดค่า Telegram ผ่าน CLI ที่ติดตั้งแล้ว จากนั้นใช้ - lane QA live ของ Telegram ซ้ำ โดยใช้ package ที่ติดตั้งนั้นเป็น SUT Gateway + - ติดตั้งตัวเลือกแพ็กเกจ OpenClaw ใน Docker รัน onboarding ของแพ็กเกจที่ติดตั้ง ตั้งค่า Telegram ผ่าน CLI ที่ติดตั้งแล้ว จากนั้นนำเลน QA สดของ Telegram มาใช้ซ้ำโดยมีแพ็กเกจที่ติดตั้งนั้นเป็น SUT Gateway - ค่าเริ่มต้นคือ `OPENCLAW_NPM_TELEGRAM_PACKAGE_SPEC=openclaw@beta`; ตั้งค่า `OPENCLAW_NPM_TELEGRAM_PACKAGE_TGZ=/path/to/openclaw-current.tgz` หรือ - `OPENCLAW_CURRENT_PACKAGE_TGZ` เพื่อทดสอบ tarball ภายในเครื่องที่ resolve แล้วแทนการ - ติดตั้งจาก registry - - ใช้ credential env ของ Telegram เดียวกันหรือแหล่ง credential Convex เดียวกับ - `pnpm openclaw qa telegram` สำหรับ automation ของ CI/release ให้ตั้งค่า + `OPENCLAW_CURRENT_PACKAGE_TGZ` เพื่อทดสอบ tarball ภายในเครื่องที่ resolve แล้วแทนการติดตั้งจาก registry + - ใช้ credentials จาก env ของ Telegram หรือแหล่ง credential ของ Convex เดียวกับ + `pnpm openclaw qa telegram` สำหรับระบบอัตโนมัติของ CI/release ให้ตั้งค่า `OPENCLAW_NPM_TELEGRAM_CREDENTIAL_SOURCE=convex` พร้อม `OPENCLAW_QA_CONVEX_SITE_URL` และ role secret หาก `OPENCLAW_QA_CONVEX_SITE_URL` และ Convex role secret มีอยู่ใน CI wrapper ของ Docker จะเลือก Convex โดยอัตโนมัติ - - `OPENCLAW_NPM_TELEGRAM_CREDENTIAL_ROLE=ci|maintainer` override ค่า shared - `OPENCLAW_QA_CREDENTIAL_ROLE` สำหรับ lane นี้เท่านั้น - - GitHub Actions เปิดเผย lane นี้เป็น workflow maintainer แบบ manual - `NPM Telegram Beta E2E` ซึ่งไม่ทำงานเมื่อ merge workflow ใช้ environment - `qa-live-shared` และ lease credential ของ Convex CI -- GitHub Actions ยังเปิดเผย `Package Acceptance` สำหรับ product proof แบบ side-run - กับ package candidate หนึ่งรายการ โดยรับ trusted ref, spec npm ที่ publish แล้ว, - URL tarball HTTPS พร้อม SHA-256 หรือ artifact tarball จาก run อื่น อัปโหลด - `openclaw-current.tgz` ที่ normalize แล้วเป็น `package-under-test` จากนั้นเรียกใช้ - Docker E2E scheduler ที่มีอยู่ด้วย profile lane smoke, package, product, full หรือ custom - ตั้งค่า `telegram_mode=mock-openai` หรือ `live-frontier` เพื่อเรียกใช้ workflow QA - ของ Telegram กับ artifact `package-under-test` เดียวกัน - - product proof ของ beta ล่าสุด: + - wrapper ตรวจสอบ env ของ credential สำหรับ Telegram หรือ Convex บนโฮสต์ก่อนงาน build/install ของ Docker ตั้งค่า `OPENCLAW_NPM_TELEGRAM_SKIP_CREDENTIAL_PREFLIGHT=1` + เฉพาะเมื่อจงใจดีบักการตั้งค่าก่อนมี credential เท่านั้น + - `OPENCLAW_NPM_TELEGRAM_CREDENTIAL_ROLE=ci|maintainer` override + `OPENCLAW_QA_CREDENTIAL_ROLE` ที่ใช้ร่วมกันสำหรับเลนนี้เท่านั้น + - GitHub Actions เปิดเผยเลนนี้เป็น workflow สำหรับ maintainer แบบ manual + `NPM Telegram Beta E2E` เลนนี้ไม่รันเมื่อ merge workflow ใช้ + environment `qa-live-shared` และ lease credential CI ของ Convex +- GitHub Actions ยังเปิดเผย `Package Acceptance` สำหรับ proof ของผลิตภัณฑ์แบบ side-run + กับแพ็กเกจตัวเลือกหนึ่งรายการ โดยรับ trusted ref, npm spec ที่เผยแพร่แล้ว, + URL tarball HTTPS พร้อม SHA-256, หรือ tarball artifact จากการรันอื่น อัปโหลด + `openclaw-current.tgz` ที่ normalize แล้วเป็น `package-under-test` จากนั้นรัน + scheduler Docker E2E ที่มีอยู่ด้วยโปรไฟล์เลน smoke, package, product, full, หรือ custom + ตั้งค่า `telegram_mode=mock-openai` หรือ `live-frontier` เพื่อรัน workflow QA ของ + Telegram กับอาร์ติแฟกต์ `package-under-test` เดียวกัน + - proof ผลิตภัณฑ์ beta ล่าสุด: ```bash gh workflow run package-acceptance.yml --ref main \ @@ -219,7 +196,7 @@ gh workflow run package-acceptance.yml --ref main \ -f telegram_mode=mock-openai ``` -- proof ด้วย URL tarball แบบเจาะจงต้องใช้ digest: +- proof ด้วย URL tarball ที่แน่นอนต้องมี digest: ```bash gh workflow run package-acceptance.yml --ref main \ @@ -229,7 +206,7 @@ gh workflow run package-acceptance.yml --ref main \ -f suite_profile=package ``` -- proof ด้วย artifact จะดาวน์โหลด artifact tarball จาก Actions run อื่น: +- proof ด้วยอาร์ติแฟกต์จะดาวน์โหลดอาร์ติแฟกต์ tarball จากการรัน Actions อื่น: ```bash gh workflow run package-acceptance.yml --ref main \ @@ -240,75 +217,61 @@ gh workflow run package-acceptance.yml --ref main \ ``` - `pnpm test:docker:plugins` - - pack และติดตั้ง build ปัจจุบันของ OpenClaw ใน Docker เริ่ม Gateway - โดยกำหนดค่า OpenAI แล้วเปิดใช้ channel/plugins ที่ bundled ผ่านการแก้ config - - ตรวจสอบว่า setup discovery ปล่อยให้ Plugin ที่ดาวน์โหลดได้แต่ยังไม่ได้กำหนดค่าไม่ปรากฏอยู่ - การซ่อม doctor ครั้งแรกที่กำหนดค่าจะติดตั้ง Plugin ที่ดาวน์โหลดได้ซึ่งขาดหายแต่ละรายการอย่างชัดเจน - และการ restart ครั้งที่สองไม่เรียกใช้การซ่อม dependency ที่ซ่อนอยู่ - - ยังติดตั้ง baseline npm รุ่นเก่าที่ทราบ เปิดใช้ Telegram ก่อนเรียกใช้ - `openclaw update --tag ` และตรวจสอบว่า doctor หลัง update ของ candidate - ล้างเศษ dependency ของ Plugin แบบ legacy โดยไม่มีการซ่อม postinstall จากฝั่ง harness + - แพ็กและติดตั้ง build ปัจจุบันของ OpenClaw ใน Docker เริ่ม Gateway + โดยตั้งค่า OpenAI แล้ว จากนั้นเปิดใช้ channel/Plugin ที่ bundled ผ่านการแก้ไข config + - ตรวจสอบว่า setup discovery ปล่อยให้ Plugin ที่ดาวน์โหลดได้และยังไม่ได้ตั้งค่าไม่ปรากฏอยู่ การซ่อม doctor ครั้งแรกที่ตั้งค่าแล้วจะติดตั้ง Plugin ที่ดาวน์โหลดได้แต่ละตัวที่หายไปอย่างชัดเจน และการ restart ครั้งที่สองจะไม่รันการซ่อมแซม dependency แบบซ่อน + - ยังติดตั้ง baseline npm รุ่นเก่าที่รู้จัก เปิดใช้ Telegram ก่อนรัน + `openclaw update --tag ` และตรวจสอบว่า doctor หลังอัปเดตของ candidate + ล้างเศษ dependency ของ Plugin เดิมโดยไม่มีการซ่อม postinstall ฝั่ง harness - `pnpm test:parallels:npm-update` - - เรียกใช้ smoke การอัปเดต packaged-install แบบ native ครอบคลุม guest ของ Parallels - แต่ละ platform ที่เลือกจะติดตั้ง package baseline ที่ร้องขอก่อน จากนั้นเรียกใช้คำสั่ง - `openclaw update` ที่ติดตั้งแล้วใน guest เดียวกัน และตรวจสอบเวอร์ชันที่ติดตั้ง - สถานะการอัปเดต ความพร้อมของ Gateway และ agent turn ภายในเครื่องหนึ่งครั้ง - - ใช้ `--platform macos`, `--platform windows` หรือ `--platform linux` ระหว่าง - iterate กับ guest หนึ่งรายการ ใช้ `--json` สำหรับ path ของ summary artifact และ - สถานะต่อ lane - - lane OpenAI ใช้ `openai/gpt-5.5` สำหรับ proof agent-turn แบบ live ตามค่าเริ่มต้น - ส่ง `--model ` หรือกำหนด - `OPENCLAW_PARALLELS_OPENAI_MODEL` เมื่อจงใจตรวจสอบ OpenAI model อื่น - - ห่อการรันภายในเครื่องที่ยาวด้วย timeout ของโฮสต์ เพื่อไม่ให้การค้างของ transport - Parallels ใช้เวลาทดสอบที่เหลือทั้งหมด: + - รัน smoke ของการอัปเดต packaged-install แบบ native ข้าม guest ของ Parallels แต่ละแพลตฟอร์มที่เลือกจะติดตั้งแพ็กเกจ baseline ที่ร้องขอก่อน จากนั้นรันคำสั่ง `openclaw update` ที่ติดตั้งแล้วใน guest เดียวกัน และตรวจสอบเวอร์ชันที่ติดตั้ง สถานะการอัปเดต ความพร้อมของ Gateway และหนึ่ง agent turn ภายในเครื่อง + - ใช้ `--platform macos`, `--platform windows`, หรือ `--platform linux` ขณะวนปรับบน guest หนึ่งตัว ใช้ `--json` สำหรับพาธอาร์ติแฟกต์สรุปและสถานะต่อเลน + - เลน OpenAI ใช้ `openai/gpt-5.5` สำหรับ proof ของ agent-turn สดเป็นค่าเริ่มต้น ส่ง `--model ` หรือตั้งค่า + `OPENCLAW_PARALLELS_OPENAI_MODEL` เมื่อจงใจตรวจสอบโมเดล OpenAI อื่น + - ครอบการรันภายในเครื่องที่ยาวด้วย timeout ของโฮสต์เพื่อไม่ให้การค้างของ transport Parallels ใช้เวลาทดสอบที่เหลือทั้งหมด: ```bash timeout --foreground 150m pnpm test:parallels:npm-update -- --json timeout --foreground 90m pnpm test:parallels:npm-update -- --platform windows --json ``` - - script เขียน log ของ lane แบบ nested ไว้ใต้ `/tmp/openclaw-parallels-npm-update.*` - ตรวจสอบ `windows-update.log`, `macos-update.log` หรือ `linux-update.log` - ก่อนสันนิษฐานว่า wrapper ชั้นนอกค้าง - - การอัปเดต Windows อาจใช้เวลา 10 ถึง 15 นาทีในงาน doctor หลัง update และงาน - update package บน guest ที่ยัง cold; ยังถือว่าปกติเมื่อ nested npm - debug log กำลังคืบหน้า - - อย่าเรียกใช้ wrapper แบบ aggregate นี้พร้อมกันกับ lane smoke รายตัวของ Parallels - macOS, Windows หรือ Linux เนื่องจากแชร์สถานะ VM และอาจชนกันในการ restore snapshot, - การให้บริการ package หรือสถานะ Gateway ของ guest - - proof หลัง update เรียกใช้พื้นผิว Plugin แบบ bundled ตามปกติ เพราะ - capability facade เช่น speech, image generation และ media - understanding ถูกโหลดผ่าน runtime API ที่ bundled แม้ agent - turn เองจะตรวจสอบเพียง response ข้อความง่ายๆ + - สคริปต์เขียนล็อกเลนแบบซ้อนใต้ `/tmp/openclaw-parallels-npm-update.*` + ตรวจสอบ `windows-update.log`, `macos-update.log`, หรือ `linux-update.log` + ก่อนสรุปว่า wrapper ชั้นนอกค้าง + - การอัปเดต Windows อาจใช้เวลา 10 ถึง 15 นาทีในงาน doctor หลังอัปเดตและการอัปเดตแพ็กเกจบน guest ที่ยังไม่อุ่น ซึ่งยังถือว่าปกติเมื่อ nested npm + debug log กำลังก้าวหน้า + - อย่ารัน wrapper แบบรวมนี้ขนานกับเลน smoke ของ Parallels สำหรับ + macOS, Windows, หรือ Linux แยกต่างหาก เพราะทั้งหมดใช้สถานะ VM ร่วมกันและอาจชนกันที่ snapshot restore, การเสิร์ฟแพ็กเกจ, หรือสถานะ Gateway ของ guest + - proof หลังอัปเดตรันพื้นผิว Plugin ที่ bundled ปกติ เพราะ facade ของ capability เช่น speech, image generation, และ media + understanding ถูกโหลดผ่าน API รันไทม์แบบ bundled แม้ตัว agent turn เองจะตรวจเพียงการตอบกลับข้อความง่าย ๆ - `pnpm openclaw qa aimock` - - เริ่มเฉพาะเซิร์ฟเวอร์ provider AIMock ภายในเครื่องสำหรับการทดสอบ smoke ของ protocol โดยตรง + - เริ่มเฉพาะเซิร์ฟเวอร์ผู้ให้บริการ AIMock ภายในเครื่องสำหรับการทดสอบ smoke ของ protocol โดยตรง - `pnpm openclaw qa matrix` - - เรียกใช้ lane QA live ของ Matrix กับ homeserver Tuwunel แบบใช้แล้วทิ้งที่อิงกับ Docker เฉพาะ source-checkout เท่านั้น — packaged install ไม่ได้ ship `qa-lab` - - CLI เต็ม, catalog ของ profile/scenario, env var และ layout artifact: [Matrix QA](/th/concepts/qa-matrix) + - รันเลน QA สดของ Matrix กับ homeserver Tuwunel แบบใช้แล้วทิ้งที่อ้างอิง Docker เฉพาะ source-checkout เท่านั้น — การติดตั้งแบบแพ็กเกจไม่ได้จัดส่ง `qa-lab` + - CLI เต็ม, แค็ตตาล็อก profile/scenario, env vars, และเลย์เอาต์อาร์ติแฟกต์: [Matrix QA](/th/concepts/qa-matrix) - `pnpm openclaw qa telegram` - - เรียกใช้ lane QA live ของ Telegram กับ private group จริงโดยใช้ driver และ token ของ SUT bot จาก env - - ต้องมี `OPENCLAW_QA_TELEGRAM_GROUP_ID`, `OPENCLAW_QA_TELEGRAM_DRIVER_BOT_TOKEN` และ `OPENCLAW_QA_TELEGRAM_SUT_BOT_TOKEN` group id ต้องเป็น chat id ของ Telegram แบบตัวเลข - - รองรับ `--credential-source convex` สำหรับ credential แบบ pooled ที่แชร์กัน ใช้โหมด env เป็นค่าเริ่มต้น หรือกำหนด `OPENCLAW_QA_CREDENTIAL_SOURCE=convex` เพื่อเลือกใช้ lease แบบ pooled - - ออกด้วยสถานะไม่เป็นศูนย์เมื่อสถานการณ์ใดล้มเหลว ใช้ `--allow-failures` เมื่อคุณ - ต้องการ artifact โดยไม่มี exit code ที่ล้มเหลว - - ต้องใช้ bot สองตัวที่แตกต่างกันใน private group เดียวกัน โดย SUT bot ต้องเปิดเผย username ของ Telegram - - เพื่อการสังเกต bot-to-bot ที่เสถียร ให้เปิดใช้ Bot-to-Bot Communication Mode ใน `@BotFather` สำหรับ bot ทั้งสองตัว และตรวจสอบว่า driver bot สังเกต traffic ของ bot ใน group ได้ - - เขียนรายงาน QA ของ Telegram, สรุป และ artifact observed-messages ไว้ใต้ `.artifacts/qa-e2e/...` สถานการณ์ที่มีการตอบกลับรวม RTT ตั้งแต่คำขอส่งของ driver ไปจนถึง reply ของ SUT ที่สังเกตได้ + - รันเลน QA สดของ Telegram กับกลุ่มส่วนตัวจริงโดยใช้ token ของ driver และ SUT bot จาก env + - ต้องมี `OPENCLAW_QA_TELEGRAM_GROUP_ID`, `OPENCLAW_QA_TELEGRAM_DRIVER_BOT_TOKEN`, และ `OPENCLAW_QA_TELEGRAM_SUT_BOT_TOKEN` group id ต้องเป็น id แชต Telegram แบบตัวเลข + - รองรับ `--credential-source convex` สำหรับ credentials แบบ pooled ที่ใช้ร่วมกัน ใช้โหมด env เป็นค่าเริ่มต้น หรือตั้งค่า `OPENCLAW_QA_CREDENTIAL_SOURCE=convex` เพื่อเลือกใช้ pooled lease + - ออกด้วยสถานะไม่ใช่ศูนย์เมื่อมีสถานการณ์ใดล้มเหลว ใช้ `--allow-failures` เมื่อคุณต้องการอาร์ติแฟกต์โดยไม่มีรหัสออกที่ล้มเหลว + - ต้องมี bot สองตัวที่แตกต่างกันในกลุ่มส่วนตัวเดียวกัน โดย SUT bot ต้องเปิดเผยชื่อผู้ใช้ Telegram + - เพื่อการสังเกต bot-to-bot ที่เสถียร ให้เปิดใช้ Bot-to-Bot Communication Mode ใน `@BotFather` สำหรับ bot ทั้งสองตัว และตรวจให้แน่ใจว่า driver bot สามารถสังเกตทราฟฟิก bot ในกลุ่มได้ + - เขียนรายงาน QA ของ Telegram, สรุป, และอาร์ติแฟกต์ observed-messages ใต้ `.artifacts/qa-e2e/...` สถานการณ์ที่มีการตอบกลับรวม RTT ตั้งแต่คำขอส่งของ driver จนถึงการตอบกลับของ SUT ที่สังเกตได้ -lane transport live ใช้ contract มาตรฐานเดียวกันเพื่อไม่ให้ transport ใหม่ drift; matrix ความครอบคลุมต่อ lane อยู่ใน [ภาพรวม QA → ความครอบคลุม transport live](/th/concepts/qa-e2e-automation#live-transport-coverage) `qa-channel` คือชุด synthetic แบบกว้าง และไม่ได้เป็นส่วนหนึ่งของ matrix นั้น +เลน transport สดใช้ contract มาตรฐานเดียวกันร่วมกันเพื่อไม่ให้ transport ใหม่คลาดเคลื่อน เมทริกซ์ความครอบคลุมต่อเลนอยู่ใน [ภาพรวม QA → ความครอบคลุม transport สด](/th/concepts/qa-e2e-automation#live-transport-coverage) `qa-channel` คือชุด synthetic กว้างและไม่ได้เป็นส่วนหนึ่งของเมทริกซ์นั้น -### credential Telegram ที่แชร์ผ่าน Convex (v1) +### credentials Telegram ที่ใช้ร่วมกันผ่าน Convex (v1) เมื่อเปิดใช้ `--credential-source convex` (หรือ `OPENCLAW_QA_CREDENTIAL_SOURCE=convex`) สำหรับ -`openclaw qa telegram` แล้ว QA lab จะได้ lease แบบ exclusive จาก pool ที่อิงกับ Convex, ส่ง heartbeat -ให้ lease นั้นขณะ lane กำลังทำงาน และปล่อย lease เมื่อ shutdown +`openclaw qa telegram` QA lab จะรับ lease แบบ exclusive จาก pool ที่อ้างอิง Convex, ส่ง Heartbeat +ให้ lease นั้นระหว่างที่เลนกำลังรัน, และปล่อย lease เมื่อ shutdown -โครง scaffold โปรเจกต์ Convex อ้างอิง: +scaffold โปรเจกต์ Convex อ้างอิง: - `qa/convex-credential-broker/` -env var ที่ต้องมี: +env vars ที่ต้องมี: - `OPENCLAW_QA_CONVEX_SITE_URL` (เช่น `https://your-deployment.convex.site`) - secret หนึ่งรายการสำหรับ role ที่เลือก: @@ -316,24 +279,24 @@ env var ที่ต้องมี: - `OPENCLAW_QA_CONVEX_SECRET_CI` สำหรับ `ci` - การเลือก role ของ credential: - CLI: `--credential-role maintainer|ci` - - ค่าเริ่มต้น env: `OPENCLAW_QA_CREDENTIAL_ROLE` (ค่าเริ่มต้นเป็น `ci` ใน CI, ไม่เช่นนั้นเป็น `maintainer`) + - ค่าเริ่มต้นจาก env: `OPENCLAW_QA_CREDENTIAL_ROLE` (ค่าเริ่มต้นเป็น `ci` ใน CI, มิฉะนั้นเป็น `maintainer`) -env var เสริม: +env vars ทางเลือก: - `OPENCLAW_QA_CREDENTIAL_LEASE_TTL_MS` (ค่าเริ่มต้น `1200000`) - `OPENCLAW_QA_CREDENTIAL_HEARTBEAT_INTERVAL_MS` (ค่าเริ่มต้น `30000`) - `OPENCLAW_QA_CREDENTIAL_ACQUIRE_TIMEOUT_MS` (ค่าเริ่มต้น `90000`) - `OPENCLAW_QA_CREDENTIAL_HTTP_TIMEOUT_MS` (ค่าเริ่มต้น `15000`) - `OPENCLAW_QA_CONVEX_ENDPOINT_PREFIX` (ค่าเริ่มต้น `/qa-credentials/v1`) -- `OPENCLAW_QA_CREDENTIAL_OWNER_ID` (trace id เสริม) -- `OPENCLAW_QA_ALLOW_INSECURE_HTTP=1` อนุญาต URL Convex แบบ loopback `http://` สำหรับการพัฒนา local-only +- `OPENCLAW_QA_CREDENTIAL_OWNER_ID` (trace id ทางเลือก) +- `OPENCLAW_QA_ALLOW_INSECURE_HTTP=1` อนุญาต URL Convex แบบ `http://` สำหรับ local loopback เพื่อการพัฒนาภายในเครื่องเท่านั้น `OPENCLAW_QA_CONVEX_SITE_URL` ควรใช้ `https://` ในการทำงานปกติ -คำสั่ง admin ของ maintainer (pool add/remove/list) ต้องใช้ +คำสั่ง admin สำหรับ maintainer (เพิ่ม/ลบ/แสดงรายการ pool) ต้องใช้ `OPENCLAW_QA_CONVEX_SECRET_MAINTAINER` โดยเฉพาะ -helper CLI สำหรับ maintainer: +ตัวช่วย CLI สำหรับ maintainer: ```bash pnpm openclaw qa credentials doctor @@ -342,9 +305,9 @@ pnpm openclaw qa credentials list --kind telegram pnpm openclaw qa credentials remove --credential-id ``` -ใช้ `doctor` ก่อนการรัน live เพื่อตรวจสอบ URL ไซต์ Convex, secret ของ broker, -endpoint prefix, HTTP timeout และความสามารถในการเข้าถึง admin/list โดยไม่พิมพ์ -ค่า secret ใช้ `--json` สำหรับ output ที่อ่านโดยเครื่องได้ใน script และ utility ของ CI +ใช้ `doctor` ก่อนการรันแบบ live เพื่อตรวจสอบ URL ไซต์ Convex, secret ของ broker, +prefix ของ endpoint, HTTP timeout และการเข้าถึง admin/list โดยไม่พิมพ์ +ค่า secret ใช้ `--json` สำหรับเอาต์พุตที่เครื่องอ่านได้ในสคริปต์และยูทิลิตี CI สัญญา endpoint เริ่มต้น (`OPENCLAW_QA_CONVEX_SITE_URL` + `/qa-credentials/v1`): @@ -358,14 +321,14 @@ endpoint prefix, HTTP timeout และความสามารถในก - `POST /release` - คำขอ: `{ kind, ownerId, actorRole, credentialId, leaseToken }` - สำเร็จ: `{ status: "ok" }` (หรือ `2xx` ว่าง) -- `POST /admin/add` (เฉพาะความลับของผู้ดูแล) +- `POST /admin/add` (secret สำหรับ maintainer เท่านั้น) - คำขอ: `{ kind, actorId, payload, note?, status? }` - สำเร็จ: `{ status: "ok", credential }` -- `POST /admin/remove` (เฉพาะความลับของผู้ดูแล) +- `POST /admin/remove` (secret สำหรับ maintainer เท่านั้น) - คำขอ: `{ credentialId, actorId }` - สำเร็จ: `{ status: "ok", changed, credential }` - - ตัวป้องกัน lease ที่ใช้งานอยู่: `{ status: "error", code: "LEASE_ACTIVE", ... }` -- `POST /admin/list` (เฉพาะความลับของผู้ดูแล) + - ตัวป้องกัน lease ที่ยัง active: `{ status: "error", code: "LEASE_ACTIVE", ... }` +- `POST /admin/list` (secret สำหรับ maintainer เท่านั้น) - คำขอ: `{ kind?, status?, includePayload?, limit? }` - สำเร็จ: `{ status: "ok", credentials, count }` @@ -375,45 +338,45 @@ endpoint prefix, HTTP timeout และความสามารถในก - `groupId` ต้องเป็นสตริงรหัสแชต Telegram แบบตัวเลข - `admin/add` ตรวจสอบรูปแบบนี้สำหรับ `kind: "telegram"` และปฏิเสธ payload ที่มีรูปแบบไม่ถูกต้อง -### การเพิ่มช่องทางใน QA +### การเพิ่มช่องทางไปยัง QA -ชื่อสถาปัตยกรรมและตัวช่วยสถานการณ์สำหรับอะแดปเตอร์ช่องทางใหม่อยู่ใน [ภาพรวม QA → การเพิ่มช่องทาง](/th/concepts/qa-e2e-automation#adding-a-channel) เกณฑ์ขั้นต่ำ: ใช้งานตัวรัน transport บน seam โฮสต์ `qa-lab` ที่ใช้ร่วมกัน, ประกาศ `qaRunners` ใน manifest ของ Plugin, เมานต์เป็น `openclaw qa `, และเขียนสถานการณ์ใต้ `qa/scenarios/` +สถาปัตยกรรมและชื่อ scenario-helper สำหรับ adapter ช่องทางใหม่อยู่ใน [ภาพรวม QA → การเพิ่มช่องทาง](/th/concepts/qa-e2e-automation#adding-a-channel) เกณฑ์ขั้นต่ำคือ: implement transport runner บน seam โฮสต์ `qa-lab` ที่ใช้ร่วมกัน, ประกาศ `qaRunners` ใน manifest ของ Plugin, mount เป็น `openclaw qa ` และเขียน scenario ภายใต้ `qa/scenarios/` ## ชุดทดสอบ (อะไรทำงานที่ไหน) -ให้มองชุดทดสอบเป็น “ความสมจริงที่เพิ่มขึ้น” (และความไม่เสถียร/ต้นทุนที่เพิ่มขึ้น): +ให้คิดว่าชุดทดสอบเป็น “ความสมจริงที่เพิ่มขึ้น” (พร้อมความไม่เสถียร/ต้นทุนที่เพิ่มขึ้น): -### หน่วย / อินทิเกรชัน (ค่าเริ่มต้น) +### Unit / integration (ค่าเริ่มต้น) - คำสั่ง: `pnpm test` -- คอนฟิก: การรันที่ไม่ได้ระบุเป้าหมายใช้ชุด shard `vitest.full-*.config.ts` และอาจขยาย shard แบบหลายโปรเจกต์เป็นคอนฟิกต่อโปรเจกต์เพื่อการจัดตารางแบบขนาน -- ไฟล์: รายการ core/unit ใต้ `src/**/*.test.ts`, `packages/**/*.test.ts`, และ `test/**/*.test.ts`; การทดสอบหน่วย UI รันใน shard `unit-ui` เฉพาะ +- การกำหนดค่า: การรันที่ไม่ได้ target ใช้ชุด shard `vitest.full-*.config.ts` และอาจขยาย shard แบบหลายโปรเจกต์เป็น config รายโปรเจกต์สำหรับการจัดตารางแบบขนาน +- ไฟล์: inventory ของ core/unit ภายใต้ `src/**/*.test.ts`, `packages/**/*.test.ts` และ `test/**/*.test.ts`; การทดสอบ UI unit ทำงานใน shard `unit-ui` เฉพาะ - ขอบเขต: - - การทดสอบหน่วยล้วน - - การทดสอบอินทิเกรชันในกระบวนการ (การยืนยันตัวตนของ Gateway, การจัดเส้นทาง, tooling, การแยกวิเคราะห์, คอนฟิก) - - regression แบบกำหนดผลได้สำหรับบั๊กที่รู้จัก + - การทดสอบ unit ล้วน + - การทดสอบ integration ใน process (การ auth ของ Gateway, routing, tooling, parsing, config) + - regression ที่กำหนดผลได้แน่นอนสำหรับ bug ที่รู้จัก - ความคาดหวัง: - - รันใน CI - - ไม่ต้องใช้คีย์จริง - - ควรเร็วและเสถียร - - การทดสอบ resolver และตัวโหลด public-surface ต้องพิสูจน์พฤติกรรม fallback ของ `api.js` และ + - ทำงานใน CI + - ไม่ต้องใช้ key จริง + - ควรรวดเร็วและเสถียร + - การทดสอบ resolver และ public-surface loader ต้องพิสูจน์พฤติกรรม fallback ของ `api.js` และ `runtime-api.js` แบบกว้างด้วย fixture Plugin ขนาดเล็กที่สร้างขึ้น ไม่ใช่ - API ซอร์สของ Plugin ที่ bundled จริง การโหลด API ของ Plugin จริงควรอยู่ใน + API ซอร์สของ Plugin ที่ bundle มาจริง การโหลด API ของ Plugin จริงอยู่ใน ชุด contract/integration ที่ Plugin เป็นเจ้าของ - - `pnpm test` ที่ไม่ได้ระบุเป้าหมายรันคอนฟิก shard ขนาดเล็กสิบสองรายการ (`core-unit-fast`, `core-unit-src`, `core-unit-security`, `core-unit-ui`, `core-unit-support`, `core-support-boundary`, `core-contracts`, `core-bundled`, `core-runtime`, `agentic`, `auto-reply`, `extensions`) แทนกระบวนการ root-project แบบเนทีฟขนาดใหญ่ตัวเดียว วิธีนี้ลด RSS สูงสุดบนเครื่องที่มีโหลด และป้องกันไม่ให้งาน auto-reply/extension แย่งทรัพยากรจนชุดทดสอบที่ไม่เกี่ยวข้องขาดช่วง - - `pnpm test --watch` ยังใช้กราฟโปรเจกต์ root `vitest.config.ts` แบบเนทีฟ เพราะลูป watch แบบหลาย shard ไม่เหมาะกับการใช้งานจริง - - `pnpm test`, `pnpm test:watch`, และ `pnpm test:perf:imports` ส่งเป้าหมายไฟล์/ไดเรกทอรีที่ระบุชัดผ่านเลนที่มีขอบเขตก่อน ดังนั้น `pnpm test extensions/discord/src/monitor/message-handler.preflight.test.ts` จึงไม่ต้องเสียต้นทุนเริ่มต้นเต็มของ root project - - `pnpm test:changed` ขยาย path ของ git ที่เปลี่ยนเป็นเลนขอบเขตราคาถูกตามค่าเริ่มต้น: การแก้ไขทดสอบโดยตรง, ไฟล์ sibling `*.test.ts`, การแมปซอร์สที่ระบุชัด, และตัวพึ่งพาในกราฟ import ภายใน การแก้ไขคอนฟิก/setup/package จะไม่รันการทดสอบแบบกว้าง เว้นแต่คุณใช้ `OPENCLAW_TEST_CHANGED_BROAD=1 pnpm test:changed` อย่างชัดเจน - - `pnpm check:changed` คือ gate ตรวจสอบ local อัจฉริยะปกติสำหรับงานแคบ มันจัดประเภท diff เป็น core, การทดสอบ core, extensions, การทดสอบ extension, apps, docs, เมทาดาทา release, tooling Docker สด, และ tooling จากนั้นรันคำสั่ง typecheck, lint, และ guard ที่ตรงกัน มันไม่รันการทดสอบ Vitest; เรียก `pnpm test:changed` หรือ `pnpm test ` แบบระบุชัดสำหรับหลักฐานการทดสอบ การ bump เวอร์ชันที่เป็น release metadata-only รันการตรวจ version/config/root-dependency แบบเจาะจง โดยมี guard ที่ปฏิเสธการเปลี่ยน package นอกฟิลด์ version ระดับบนสุด - - การแก้ไข harness Docker ACP สดรันการตรวจแบบมุ่งเน้น: syntax shell สำหรับสคริปต์ auth ของ Docker สดและ dry-run ของ scheduler Docker สด การเปลี่ยนแปลง `package.json` จะรวมเฉพาะเมื่อ diff จำกัดอยู่ที่ `scripts["test:docker:live-*"]`; การแก้ไข dependency, export, version, และพื้นผิว package อื่นยังใช้ guard ที่กว้างกว่า - - การทดสอบหน่วยที่ import เบาจาก agents, commands, plugins, ตัวช่วย auto-reply, `plugin-sdk`, และพื้นที่ utility ล้วนที่คล้ายกัน จะถูกส่งผ่านเลน `unit-fast` ซึ่งข้าม `test/setup-openclaw-runtime.ts`; ไฟล์ที่มีสถานะหรือ runtime หนักยังอยู่บนเลนเดิม - - ไฟล์ซอร์สตัวช่วย `plugin-sdk` และ `commands` บางรายการยังแมปการรัน changed-mode ไปยังการทดสอบ sibling ที่ระบุชัดในเลนเบาเหล่านั้น เพื่อให้การแก้ไขตัวช่วยไม่ต้องรันชุดหนักทั้งหมดของไดเรกทอรีนั้นซ้ำ - - `auto-reply` มี bucket เฉพาะสำหรับตัวช่วย core ระดับบน, การทดสอบอินทิเกรชัน `reply.*` ระดับบน, และ subtree `src/auto-reply/reply/**` CI ยังแบ่ง subtree reply เพิ่มเป็น shard agent-runner, dispatch, และ commands/state-routing เพื่อไม่ให้ bucket ที่ import หนักตัวเดียวครอบครอง tail ของ Node ทั้งหมด - - CI ของ PR/main ปกติจงใจข้ามการกวาด batch extension และ shard `agentic-plugins` เฉพาะ release Full Release Validation dispatch workflow ลูก `Plugin Prerelease` แยกต่างหากสำหรับชุดที่หนักด้าน plugin/extension เหล่านั้นบน release candidate + - `pnpm test` ที่ไม่ได้ target จะรัน config shard ขนาดเล็กสิบสองชุด (`core-unit-fast`, `core-unit-src`, `core-unit-security`, `core-unit-ui`, `core-unit-support`, `core-support-boundary`, `core-contracts`, `core-bundled`, `core-runtime`, `agentic`, `auto-reply`, `extensions`) แทน process root-project native ขนาดใหญ่ชุดเดียว วิธีนี้ลด RSS สูงสุดบนเครื่องที่มีโหลด และป้องกันไม่ให้งาน auto-reply/extension แย่งทรัพยากรจน suite ที่ไม่เกี่ยวข้องขาดทรัพยากร + - `pnpm test --watch` ยังใช้ graph โปรเจกต์ `vitest.config.ts` root native เพราะ watch loop แบบหลาย shard ไม่เหมาะในทางปฏิบัติ + - `pnpm test`, `pnpm test:watch` และ `pnpm test:perf:imports` จะ route target ไฟล์/ไดเรกทอรีที่ระบุชัดเจนผ่าน scoped lanes ก่อน ดังนั้น `pnpm test extensions/discord/src/monitor/message-handler.preflight.test.ts` จึงหลีกเลี่ยงต้นทุน startup ของ root project ทั้งหมด + - `pnpm test:changed` ขยาย path ของ git ที่เปลี่ยนเป็น scoped lanes ราคาถูกตามค่าเริ่มต้น: การแก้ไข test โดยตรง, ไฟล์ sibling `*.test.ts`, การ mapping ซอร์สที่ระบุชัดเจน และ dependent ใน import-graph แบบ local การแก้ไข config/setup/package จะไม่รัน test แบบกว้าง เว้นแต่คุณจะใช้ `OPENCLAW_TEST_CHANGED_BROAD=1 pnpm test:changed` อย่างชัดเจน + - `pnpm check:changed` คือ smart local check gate ปกติสำหรับงานขอบเขตแคบ โดยจัดประเภท diff เป็น core, core tests, extensions, extension tests, apps, docs, release metadata, live Docker tooling และ tooling จากนั้นรัน typecheck, lint และคำสั่ง guard ที่ตรงกัน คำสั่งนี้ไม่รัน Vitest test; เรียก `pnpm test:changed` หรือ `pnpm test ` ที่ระบุชัดเจนเพื่อใช้เป็นหลักฐานการทดสอบ การ bump version ที่เป็น release metadata เท่านั้นจะรันการตรวจ version/config/root-dependency แบบเจาะจง พร้อม guard ที่ปฏิเสธการเปลี่ยนแปลง package นอก field version ระดับบนสุด + - การแก้ไข live Docker ACP harness จะรันการตรวจเฉพาะจุด: syntax ของ shell สำหรับสคริปต์ live Docker auth และ dry-run ของ live Docker scheduler การเปลี่ยนแปลง `package.json` จะรวมเฉพาะเมื่อ diff จำกัดอยู่ที่ `scripts["test:docker:live-*"]`; การแก้ไข dependency, export, version และพื้นผิว package อื่น ๆ ยังใช้ guard ที่กว้างกว่า + - การทดสอบ unit แบบ import-light จาก agents, commands, plugins, helper ของ auto-reply, `plugin-sdk` และพื้นที่ utility ล้วนที่คล้ายกัน จะ route ผ่าน lane `unit-fast` ซึ่งข้าม `test/setup-openclaw-runtime.ts`; ไฟล์ที่มี stateful/runtime-heavy ยังคงอยู่บน lane เดิม + - ไฟล์ซอร์ส helper บางไฟล์ใน `plugin-sdk` และ `commands` ยัง map การรัน changed-mode ไปยัง test sibling ที่ระบุชัดเจนใน lane เบาเหล่านั้นด้วย ดังนั้นการแก้ไข helper จึงหลีกเลี่ยงการรัน suite หนักทั้งหมดของไดเรกทอรีนั้นอีกครั้ง + - `auto-reply` มี bucket เฉพาะสำหรับ helper core ระดับบน, test integration `reply.*` ระดับบน และ subtree `src/auto-reply/reply/**` CI ยังแยก subtree reply เพิ่มเป็น shard agent-runner, dispatch และ commands/state-routing เพื่อไม่ให้ bucket ที่ import-heavy หนึ่งชุดครอง Node tail ทั้งหมด + - CI ปกติของ PR/main ตั้งใจข้าม extension batch sweep และ shard `agentic-plugins` ที่ใช้เฉพาะ release Full Release Validation dispatch workflow ลูก `Plugin Prerelease` แยกต่างหากสำหรับ suite ที่เน้น plugin/extension เหล่านั้นบน release candidate @@ -421,358 +384,356 @@ endpoint prefix, HTTP timeout และความสามารถในก - เมื่อคุณเปลี่ยน input ของการค้นพบ message-tool หรือ context runtime ของ compaction ให้คง coverage ทั้งสองระดับไว้ - - เพิ่ม regression ของตัวช่วยแบบมุ่งเน้นสำหรับขอบเขตการจัดเส้นทางและ normalization - แบบล้วน - - รักษาชุดอินทิเกรชันของ embedded runner ให้แข็งแรง: + - เพิ่ม regression ของ helper แบบเจาะจงสำหรับขอบเขต pure routing และ normalization + - รักษา suite integration ของ embedded runner ให้ healthy: `src/agents/pi-embedded-runner/compact.hooks.test.ts`, - `src/agents/pi-embedded-runner/run.overflow-compaction.test.ts`, และ + `src/agents/pi-embedded-runner/run.overflow-compaction.test.ts` และ `src/agents/pi-embedded-runner/run.overflow-compaction.loop.test.ts` - - ชุดเหล่านั้นตรวจสอบว่า id แบบมีขอบเขตและพฤติกรรม Compaction ยังคงไหล - ผ่าน path `run.ts` / `compact.ts` จริง; การทดสอบเฉพาะตัวช่วย - ไม่ใช่สิ่งทดแทนที่เพียงพอสำหรับ path อินทิเกรชันเหล่านั้น + - Suite เหล่านั้นตรวจสอบว่า scoped ids และพฤติกรรม compaction ยังคงไหลผ่าน + path `run.ts` / `compact.ts` จริง; test เฉพาะ helper ไม่ใช่ + สิ่งทดแทนที่เพียงพอสำหรับ path integration เหล่านั้น - - คอนฟิก Vitest พื้นฐานตั้งค่าเริ่มต้นเป็น `threads` - - คอนฟิก Vitest ที่ใช้ร่วมกันตรึง `isolate: false` และใช้ตัวรัน - แบบไม่ isolated ในโปรเจกต์ root, e2e, และคอนฟิก live - - เลน UI root ยังคง setup และ optimizer `jsdom` ของตัวเอง แต่รันบนตัวรัน - แบบไม่ isolated ที่ใช้ร่วมกันเช่นกัน - - shard `pnpm test` แต่ละรายการสืบทอดค่าเริ่มต้น `threads` + `isolate: false` - เดียวกันจากคอนฟิก Vitest ที่ใช้ร่วมกัน - - `scripts/run-vitest.mjs` เพิ่ม `--no-maglev` ให้กระบวนการ Node ลูกของ Vitest + - ค่าเริ่มต้นของ config Vitest พื้นฐานคือ `threads` + - config Vitest ที่ใช้ร่วมกันกำหนด `isolate: false` และใช้ + runner แบบ non-isolated ข้าม root projects, e2e และ config live + - lane UI root คงการตั้งค่า `jsdom` และ optimizer ของตัวเองไว้ แต่ก็ทำงานบน + runner non-isolated ที่ใช้ร่วมกันเช่นกัน + - shard `pnpm test` แต่ละชุดสืบทอดค่าเริ่มต้น `threads` + `isolate: false` + เดียวกันจาก config Vitest ที่ใช้ร่วมกัน + - `scripts/run-vitest.mjs` เพิ่ม `--no-maglev` สำหรับ process Node ลูกของ Vitest ตามค่าเริ่มต้นเพื่อลด V8 compile churn ระหว่างการรัน local ขนาดใหญ่ - ตั้ง `OPENCLAW_VITEST_ENABLE_MAGLEV=1` เพื่อเปรียบเทียบกับพฤติกรรม V8 - มาตรฐาน + ตั้งค่า `OPENCLAW_VITEST_ENABLE_MAGLEV=1` เพื่อเปรียบเทียบกับพฤติกรรม V8 + แบบ stock - - `pnpm changed:lanes` แสดงว่า diff กระตุ้นเลนสถาปัตยกรรมใด - - hook pre-commit มีไว้สำหรับการฟอร์แมตเท่านั้น มัน stage ไฟล์ที่ฟอร์แมตแล้วใหม่และ - ไม่รัน lint, typecheck, หรือการทดสอบ + - `pnpm changed:lanes` แสดงว่า diff ทำให้ lane เชิงสถาปัตยกรรมใดทำงาน + - pre-commit hook ทำเฉพาะ formatting โดย restage ไฟล์ที่ format แล้ว และ + ไม่รัน lint, typecheck หรือ test - รัน `pnpm check:changed` อย่างชัดเจนก่อน handoff หรือ push เมื่อคุณ - ต้องการ gate ตรวจสอบ local อัจฉริยะ - - `pnpm test:changed` ส่งผ่านเลนที่มีขอบเขตราคาถูกตามค่าเริ่มต้น ใช้ + ต้องการ smart local check gate + - `pnpm test:changed` route ผ่าน scoped lanes ราคาถูกตามค่าเริ่มต้น ใช้ `OPENCLAW_TEST_CHANGED_BROAD=1 pnpm test:changed` เฉพาะเมื่อ agent - ตัดสินว่าการแก้ไข harness, คอนฟิก, package, หรือ contract ต้องการ - coverage Vitest ที่กว้างขึ้นจริง - - `pnpm test:max` และ `pnpm test:changed:max` คงพฤติกรรมการจัดเส้นทาง - เดิมไว้ เพียงแต่มีเพดาน worker สูงกว่า - - การปรับขนาด worker local อัตโนมัติจงใจตั้งไว้อย่างระมัดระวังและลดระดับ - เมื่อค่า load average ของโฮสต์สูงอยู่แล้ว ดังนั้นการรัน Vitest พร้อมกันหลายรายการ - จะสร้างผลกระทบน้อยลงตามค่าเริ่มต้น - - คอนฟิก Vitest พื้นฐานทำเครื่องหมายโปรเจกต์/ไฟล์คอนฟิกเป็น - `forceRerunTriggers` เพื่อให้การรันซ้ำใน changed-mode ยังคงถูกต้องเมื่อ wiring - ของการทดสอบเปลี่ยน - - คอนฟิกคง `OPENCLAW_VITEST_FS_MODULE_CACHE` ให้เปิดใช้งานบนโฮสต์ที่รองรับ; - ตั้ง `OPENCLAW_VITEST_FS_MODULE_CACHE_PATH=/abs/path` หากคุณต้องการ - ตำแหน่ง cache ชัดเจนหนึ่งตำแหน่งสำหรับการ profiling โดยตรง + ตัดสินว่าการแก้ไข harness, config, package หรือ contract จำเป็นต้องมี + coverage Vitest ที่กว้างกว่า + - `pnpm test:max` และ `pnpm test:changed:max` คงพฤติกรรม routing เดิม + เพียงแต่ใช้ worker cap ที่สูงขึ้น + - การ auto-scale worker แบบ local ตั้งใจให้ conservative และถอยลง + เมื่อ load average ของโฮสต์สูงอยู่แล้ว ดังนั้นการรัน Vitest พร้อมกันหลายชุด + จึงสร้างผลกระทบน้อยลงตามค่าเริ่มต้น + - config Vitest พื้นฐานทำเครื่องหมาย projects/config files เป็น + `forceRerunTriggers` เพื่อให้การ rerun แบบ changed-mode ยังคงถูกต้องเมื่อ + wiring ของ test เปลี่ยน + - config เปิด `OPENCLAW_VITEST_FS_MODULE_CACHE` ไว้บนโฮสต์ที่รองรับ; + ตั้งค่า `OPENCLAW_VITEST_FS_MODULE_CACHE_PATH=/abs/path` หากคุณต้องการ + location cache ที่ระบุชัดเจนหนึ่งแห่งสำหรับ profiling โดยตรง - - `pnpm test:perf:imports` เปิดการรายงานระยะเวลา import ของ Vitest พร้อม - output รายละเอียด import-breakdown - - `pnpm test:perf:imports:changed` จำกัดมุมมอง profiling เดียวกันให้อยู่กับ + - `pnpm test:perf:imports` เปิดการรายงาน import-duration ของ Vitest พร้อม + เอาต์พุต import-breakdown + - `pnpm test:perf:imports:changed` จำกัดมุมมอง profiling เดียวกันไว้ที่ ไฟล์ที่เปลี่ยนตั้งแต่ `origin/main` - - ข้อมูลเวลา shard ถูกเขียนไปที่ `.artifacts/vitest-shard-timings.json` - การรัน whole-config ใช้ path คอนฟิกเป็น key; shard CI แบบ include-pattern - ต่อท้ายชื่อ shard เพื่อให้ shard ที่ถูกกรองสามารถติดตามแยกกันได้ - - เมื่อการทดสอบ hot หนึ่งรายการยังใช้เวลาส่วนใหญ่กับ startup imports - ให้เก็บ dependency หนักไว้หลัง seam local `*.runtime.ts` แคบ ๆ และ - mock seam นั้นโดยตรงแทนการ deep-import ตัวช่วย runtime เพียง - เพื่อส่งต่อผ่าน `vi.mock(...)` + - ข้อมูล timing ของ shard ถูกเขียนไปที่ `.artifacts/vitest-shard-timings.json` + การรันทั้ง config ใช้ path ของ config เป็น key; shard CI แบบ include-pattern + จะต่อท้ายชื่อ shard เพื่อให้ติดตาม shard ที่ filtered แยกกันได้ + - เมื่อ test ที่ร้อนหนึ่งตัวยังใช้เวลาส่วนใหญ่กับ startup imports + ให้เก็บ dependency หนักไว้หลัง seam local `*.runtime.ts` ที่แคบ และ + mock seam นั้นโดยตรงแทนการ deep-import runtime helper เพียงเพื่อ + ส่งต่อเข้า `vi.mock(...)` - `pnpm test:perf:changed:bench -- --ref ` เปรียบเทียบ - `test:changed` ที่ถูกจัดเส้นทางกับ path root-project แบบเนทีฟสำหรับ diff ที่ commit แล้วนั้น - และพิมพ์ wall time พร้อม RSS สูงสุดของ macOS - - `pnpm test:perf:changed:bench -- --worktree` benchmark tree ปัจจุบัน - ที่ยัง dirty โดยส่งรายการไฟล์ที่เปลี่ยนผ่าน - `scripts/test-projects.mjs` และคอนฟิก Vitest root - - `pnpm test:perf:profile:main` เขียนโปรไฟล์ CPU ของ main-thread สำหรับ - overhead การเริ่มต้นและ transform ของ Vitest/Vite - - `pnpm test:perf:profile:runner` เขียนโปรไฟล์ CPU+heap ของ runner สำหรับชุด - unit โดยปิด file parallelism + `test:changed` ที่ route แล้วกับ path root-project native สำหรับ diff ที่ commit แล้วนั้น + และพิมพ์ wall time พร้อม max RSS ของ macOS + - `pnpm test:perf:changed:bench -- --worktree` benchmark tree ปัจจุบันที่ dirty + โดย route รายการไฟล์ที่เปลี่ยนผ่าน + `scripts/test-projects.mjs` และ config Vitest root + - `pnpm test:perf:profile:main` เขียน CPU profile ของ main-thread สำหรับ + overhead ของ startup และ transform ใน Vitest/Vite + - `pnpm test:perf:profile:runner` เขียน CPU+heap profile ของ runner สำหรับ + suite unit โดยปิด file parallelism -### เสถียรภาพ (Gateway) +### Stability (Gateway) - คำสั่ง: `pnpm test:stability:gateway` -- คอนฟิก: `vitest.gateway.config.ts`, บังคับให้ใช้ worker หนึ่งตัว +- การกำหนดค่า: `vitest.gateway.config.ts`, บังคับให้ใช้ worker เดียว - ขอบเขต: - - เริ่ม Gateway แบบ loopback จริงโดยเปิด diagnostics ตามค่าเริ่มต้น - - ขับ churn ของข้อความ Gateway, memory, และ payload ขนาดใหญ่แบบสังเคราะห์ผ่าน path event diagnostic + - เริ่ม Gateway loopback จริงโดยเปิด diagnostics เป็นค่าเริ่มต้น + - ขับ churn ของข้อความ Gateway, memory และ large-payload สังเคราะห์ผ่าน path เหตุการณ์ diagnostic - query `diagnostics.stability` ผ่าน Gateway WS RPC - - ครอบคลุมตัวช่วย persistence ของ diagnostic stability bundle - - ยืนยันว่า recorder ยังคงมีขอบเขตจำกัด, ตัวอย่าง RSS สังเคราะห์อยู่ใต้ budget ความกดดัน, และความลึกของคิวต่อ session ระบายกลับเป็นศูนย์ + - ครอบคลุม helper persistence ของ diagnostic stability bundle + - assert ว่า recorder ยังคงมีขอบเขตจำกัด, sample RSS สังเคราะห์อยู่ต่ำกว่า pressure budget และความลึก queue ต่อ session ระบายกลับเป็นศูนย์ - ความคาดหวัง: - - ปลอดภัยสำหรับ CI และไม่ต้องใช้คีย์ - - เลนแคบสำหรับการติดตาม stability-regression ไม่ใช่สิ่งทดแทนชุด Gateway เต็ม + - ปลอดภัยสำหรับ CI และไม่ต้องใช้ key + - lane แคบสำหรับการติดตาม stability-regression ไม่ใช่สิ่งทดแทน suite Gateway ทั้งหมด -### E2E (gateway smoke) +### E2E (smoke test ของ Gateway) - คำสั่ง: `pnpm test:e2e` -- คอนฟิก: `vitest.e2e.config.ts` -- ไฟล์: `src/**/*.e2e.test.ts`, `test/**/*.e2e.test.ts`, และการทดสอบ E2E ของ bundled-plugin ใต้ `extensions/` -- ค่าเริ่มต้น runtime: - - ใช้ `threads` ของ Vitest พร้อม `isolate: false` ให้ตรงกับส่วนที่เหลือของ repo - - ใช้ worker แบบ adaptive (CI: สูงสุด 2, local: ค่าเริ่มต้น 1) - - รันในโหมด silent ตามค่าเริ่มต้นเพื่อลด overhead I/O ของ console -- override ที่มีประโยชน์: - - `OPENCLAW_E2E_WORKERS=` เพื่อบังคับจำนวน worker (จำกัดสูงสุดที่ 16) - - `OPENCLAW_E2E_VERBOSE=1` เพื่อเปิด output console แบบละเอียดอีกครั้ง +- การกำหนดค่า: `vitest.e2e.config.ts` +- ไฟล์: `src/**/*.e2e.test.ts`, `test/**/*.e2e.test.ts` และการทดสอบ E2E ของ Plugin ที่บันเดิลไว้ภายใต้ `extensions/` +- ค่าเริ่มต้นของรันไทม์: + - ใช้ Vitest `threads` พร้อม `isolate: false` ให้ตรงกับส่วนที่เหลือของรีโป + - ใช้เวิร์กเกอร์แบบปรับตามสภาพแวดล้อม (CI: สูงสุด 2, local: ค่าเริ่มต้น 1) + - รันในโหมดเงียบตามค่าเริ่มต้นเพื่อลดโอเวอร์เฮด I/O ของคอนโซล +- การแทนที่ค่าที่มีประโยชน์: + - `OPENCLAW_E2E_WORKERS=` เพื่อบังคับจำนวนเวิร์กเกอร์ (จำกัดสูงสุดที่ 16) + - `OPENCLAW_E2E_VERBOSE=1` เพื่อเปิดเอาต์พุตคอนโซลแบบละเอียดอีกครั้ง - ขอบเขต: - - พฤติกรรม end-to-end ของ Gateway หลาย instance - - พื้นผิว WebSocket/HTTP, การจับคู่ node, และ networking ที่หนักกว่า + - พฤติกรรมแบบ end-to-end ของ gateway หลายอินสแตนซ์ + - พื้นผิว WebSocket/HTTP, การจับคู่ node และระบบเครือข่ายที่หนักกว่า - ความคาดหวัง: - - รันใน CI (เมื่อเปิดใช้งานใน pipeline) + - รันใน CI (เมื่อเปิดใช้ใน pipeline) - ไม่ต้องใช้คีย์จริง - - มีส่วนที่เคลื่อนไหวมากกว่าการทดสอบหน่วย (อาจช้ากว่า) + - มีชิ้นส่วนที่เคลื่อนไหวมากกว่าการทดสอบหน่วย (อาจช้ากว่า) -### E2E: smoke backend OpenShell +### E2E: สโมกของแบ็กเอนด์ OpenShell - คำสั่ง: `pnpm test:e2e:openshell` - ไฟล์: `extensions/openshell/src/backend.e2e.test.ts` - ขอบเขต: - - เริ่ม OpenShell Gateway แบบแยกเดี่ยวบนโฮสต์ผ่าน Docker + - เริ่ม Gateway OpenShell แบบแยกบนโฮสต์ผ่าน Docker - สร้าง sandbox จาก Dockerfile ชั่วคราวในเครื่อง - - ทดสอบ backend ของ OpenShell ใน OpenClaw ผ่าน `sandbox ssh-config` จริง + การ exec ผ่าน SSH - - ตรวจสอบพฤติกรรมระบบไฟล์แบบ remote-canonical ผ่านบริดจ์ fs ของ sandbox + - ทดสอบแบ็กเอนด์ OpenShell ของ OpenClaw ผ่าน `sandbox ssh-config` จริง + SSH exec + - ตรวจสอบพฤติกรรมระบบไฟล์แบบ remote-canonical ผ่าน sandbox fs bridge - ความคาดหวัง: - - ต้องเลือกเปิดใช้เท่านั้น; ไม่เป็นส่วนหนึ่งของการรัน `pnpm test:e2e` เริ่มต้น - - ต้องมี CLI `openshell` ในเครื่องพร้อม Docker daemon ที่ใช้งานได้ - - ใช้ `HOME` / `XDG_CONFIG_HOME` แบบแยกเดี่ยว แล้วทำลาย test Gateway และ sandbox -- การ override ที่มีประโยชน์: - - `OPENCLAW_E2E_OPENSHELL=1` เพื่อเปิดใช้การทดสอบเมื่อรันชุด e2e ที่กว้างขึ้นด้วยตนเอง + - ต้องเลือกเปิดใช้เท่านั้น ไม่เป็นส่วนหนึ่งของการรัน `pnpm test:e2e` ตามค่าเริ่มต้น + - ต้องมี CLI `openshell` ในเครื่องและ Docker daemon ที่ใช้งานได้ + - ใช้ `HOME` / `XDG_CONFIG_HOME` แบบแยก จากนั้นทำลาย test gateway และ sandbox +- การแทนที่ค่าที่มีประโยชน์: + - `OPENCLAW_E2E_OPENSHELL=1` เพื่อเปิดใช้การทดสอบเมื่อรันชุด e2e ที่กว้างกว่าด้วยตนเอง - `OPENCLAW_E2E_OPENSHELL_COMMAND=/path/to/openshell` เพื่อชี้ไปยังไบนารี CLI หรือสคริปต์ wrapper ที่ไม่ใช่ค่าเริ่มต้น ### Live (ผู้ให้บริการจริง + โมเดลจริง) - คำสั่ง: `pnpm test:live` - การกำหนดค่า: `vitest.live.config.ts` -- ไฟล์: `src/**/*.live.test.ts`, `test/**/*.live.test.ts` และการทดสอบ live ของ bundled-plugin ภายใต้ `extensions/` +- ไฟล์: `src/**/*.live.test.ts`, `test/**/*.live.test.ts` และการทดสอบ live ของ Plugin ที่บันเดิลไว้ภายใต้ `extensions/` - ค่าเริ่มต้น: **เปิดใช้** โดย `pnpm test:live` (ตั้งค่า `OPENCLAW_LIVE_TEST=1`) - ขอบเขต: - - “ผู้ให้บริการ/โมเดลนี้ใช้งานได้จริง _วันนี้_ ด้วย credentials จริงหรือไม่?” - - จับการเปลี่ยนแปลงรูปแบบของผู้ให้บริการ, พฤติกรรมพิเศษของ tool-calling, ปัญหา auth และพฤติกรรม rate limit + - “ผู้ให้บริการ/โมเดลนี้ใช้งานได้จริง _วันนี้_ ด้วยข้อมูลรับรองจริงหรือไม่?” + - ตรวจจับการเปลี่ยนรูปแบบของผู้ให้บริการ ความเฉพาะของการเรียกใช้เครื่องมือ ปัญหา auth และพฤติกรรม rate limit - ความคาดหวัง: - - ตั้งใจให้ไม่เสถียรสำหรับ CI (เครือข่ายจริง, นโยบายผู้ให้บริการจริง, quota, outage) + - ตั้งใจให้อยู่ไม่เสถียรสำหรับ CI (เครือข่ายจริง นโยบายผู้ให้บริการจริง quota จริง การหยุดให้บริการ) - มีค่าใช้จ่าย / ใช้ rate limit - - ควรรัน subset ที่แคบลงแทนการรัน “ทุกอย่าง” -- การรัน live จะ source `~/.profile` เพื่อดึง API key ที่ขาดหายไป -- โดยค่าเริ่มต้น การรัน live ยังแยก `HOME` และคัดลอก config/auth material ไปยัง temp test home เพื่อให้ unit fixture ไม่สามารถแก้ไข `~/.openclaw` จริงของคุณได้ + - ควรรันชุดย่อยที่จำกัดขอบเขตแทนการรัน “ทุกอย่าง” +- การรัน live จะ source `~/.profile` เพื่อรับคีย์ API ที่ขาดหาย +- ตามค่าเริ่มต้น การรัน live ยังแยก `HOME` และคัดลอกวัสดุ config/auth ไปยัง test home ชั่วคราว เพื่อไม่ให้ fixture ของการทดสอบหน่วยกลายพันธุ์ `~/.openclaw` จริงของคุณ - ตั้งค่า `OPENCLAW_LIVE_USE_REAL_HOME=1` เฉพาะเมื่อคุณตั้งใจให้การทดสอบ live ใช้ไดเรกทอรี home จริงของคุณ -- ตอนนี้ `pnpm test:live` ใช้โหมดที่เงียบกว่าเป็นค่าเริ่มต้น: ยังคงเก็บเอาต์พุตความคืบหน้า `[live] ...` แต่ปิดประกาศ `~/.profile` เพิ่มเติมและปิดเสียง log/bootstrap ของ Gateway รวมถึง Bonjour chatter ตั้งค่า `OPENCLAW_LIVE_TEST_QUIET=0` หากคุณต้องการ log startup แบบเต็มกลับมา -- การหมุนเวียน API key (เฉพาะผู้ให้บริการ): ตั้งค่า `*_API_KEYS` ด้วยรูปแบบ comma/semicolon หรือ `*_API_KEY_1`, `*_API_KEY_2` (เช่น `OPENAI_API_KEYS`, `ANTHROPIC_API_KEYS`, `GEMINI_API_KEYS`) หรือ override ต่อ live ผ่าน `OPENCLAW_LIVE_*_KEY`; การทดสอบจะ retry เมื่อได้รับ rate limit response -- เอาต์พุต progress/heartbeat: - - ตอนนี้ชุด live จะ emit บรรทัดความคืบหน้าไปยัง stderr เพื่อให้เห็นว่า provider call ที่ใช้เวลานานยังทำงานอยู่ แม้เมื่อ Vitest console capture เงียบ - - `vitest.live.config.ts` ปิดการดักจับ console ของ Vitest เพื่อให้บรรทัดความคืบหน้าของผู้ให้บริการ/Gateway stream ทันทีระหว่างการรัน live - - ปรับ heartbeat ของ direct-model ด้วย `OPENCLAW_LIVE_HEARTBEAT_MS` - - ปรับ heartbeat ของ Gateway/probe ด้วย `OPENCLAW_LIVE_GATEWAY_HEARTBEAT_MS` +- ตอนนี้ `pnpm test:live` ใช้โหมดที่เงียบกว่าเป็นค่าเริ่มต้น: ยังคงเอาต์พุตความคืบหน้า `[live] ...` ไว้ แต่ซ่อนประกาศ `~/.profile` เพิ่มเติมและปิดเสียง log การ bootstrap gateway/ข้อความ Bonjour ตั้งค่า `OPENCLAW_LIVE_TEST_QUIET=0` หากต้องการ log การเริ่มต้นแบบเต็มกลับมา +- การหมุนเวียนคีย์ API (เฉพาะผู้ให้บริการ): ตั้งค่า `*_API_KEYS` ด้วยรูปแบบ comma/semicolon หรือ `*_API_KEY_1`, `*_API_KEY_2` (ตัวอย่างเช่น `OPENAI_API_KEYS`, `ANTHROPIC_API_KEYS`, `GEMINI_API_KEYS`) หรือแทนที่ต่อ live ผ่าน `OPENCLAW_LIVE_*_KEY`; การทดสอบจะลองใหม่เมื่อได้รับการตอบสนอง rate limit +- เอาต์พุตความคืบหน้า/heartbeat: + - ตอนนี้ชุด live จะส่งบรรทัดความคืบหน้าไปยัง stderr เพื่อให้เห็นว่าการเรียกผู้ให้บริการที่ใช้เวลานานยังทำงานอยู่ แม้เมื่อการจับคอนโซลของ Vitest เงียบ + - `vitest.live.config.ts` ปิดการดักจับคอนโซลของ Vitest เพื่อให้บรรทัดความคืบหน้าของผู้ให้บริการ/gateway สตรีมทันทีระหว่างการรัน live + - ปรับ direct-model heartbeats ด้วย `OPENCLAW_LIVE_HEARTBEAT_MS` + - ปรับ gateway/probe heartbeats ด้วย `OPENCLAW_LIVE_GATEWAY_HEARTBEAT_MS` -## ควรรัน suite ใด? +## ควรรันชุดใด? ใช้ตารางตัดสินใจนี้: -- แก้ไข logic/tests: รัน `pnpm test` (และ `pnpm test:coverage` หากคุณเปลี่ยนเยอะ) -- แตะ gateway networking / WS protocol / pairing: เพิ่ม `pnpm test:e2e` -- ดีบัก “บอทของฉันล่ม” / ความล้มเหลวเฉพาะผู้ให้บริการ / tool calling: รัน `pnpm test:live` แบบจำกัดขอบเขต +- แก้ไขลอจิก/การทดสอบ: รัน `pnpm test` (และ `pnpm test:coverage` หากคุณเปลี่ยนแปลงมาก) +- แตะระบบเครือข่ายของ gateway / โปรโตคอล WS / การจับคู่: เพิ่ม `pnpm test:e2e` +- ดีบัก “บอตของฉันล่ม” / ความล้มเหลวเฉพาะผู้ให้บริการ / การเรียกใช้เครื่องมือ: รัน `pnpm test:live` แบบจำกัดขอบเขต -## การทดสอบ Live (ที่แตะเครือข่าย) +## การทดสอบ Live (แตะเครือข่าย) -สำหรับ live model matrix, smoke ของ CLI backend, smoke ของ ACP, harness ของ Codex app-server +สำหรับเมทริกซ์โมเดล live, สโมกแบ็กเอนด์ CLI, สโมก ACP, harness ของ app-server Codex และการทดสอบ live ของ media-provider ทั้งหมด (Deepgram, BytePlus, ComfyUI, image, -music, video, media harness) รวมถึงการจัดการ credentials สำหรับการรัน live โปรดดู -[การทดสอบ live suites](/th/help/testing-live) สำหรับ checklist เฉพาะด้านการอัปเดตและ -การตรวจสอบ Plugin โปรดดู -[การทดสอบ updates และ plugins](/th/help/testing-updates-plugins) +music, video, media harness) — รวมถึงการจัดการข้อมูลรับรองสำหรับการรัน live — ดู +[การทดสอบชุด live](/th/help/testing-live) สำหรับเช็กลิสต์เฉพาะด้านการอัปเดตและ +การตรวจสอบ Plugin ดู +[การทดสอบการอัปเดตและ Plugin](/th/help/testing-updates-plugins) -## Docker runners (การตรวจสอบ "ทำงานใน Linux" แบบไม่บังคับ) +## Docker runners (การตรวจสอบ “ทำงานใน Linux” แบบไม่บังคับ) -Docker runners เหล่านี้แบ่งออกเป็นสองกลุ่ม: +Docker runners เหล่านี้แบ่งเป็นสองกลุ่ม: -- Live-model runners: `test:docker:live-models` และ `test:docker:live-gateway` รันเฉพาะไฟล์ live ที่ตรงกับ profile-key ภายในอิมเมจ Docker ของ repo (`src/agents/models.profiles.live.test.ts` และ `src/gateway/gateway-models.profiles.live.test.ts`) โดย mount ไดเรกทอรี config และ workspace ในเครื่องของคุณ (และ source `~/.profile` หากถูก mount) entrypoint ในเครื่องที่ตรงกันคือ `test:live:models-profiles` และ `test:live:gateway-profiles` -- Docker live runners ตั้งค่าเริ่มต้นเป็น smoke cap ที่เล็กกว่าเพื่อให้การ sweep Docker เต็มยังใช้งานได้จริง: +- ตัวรัน live-model: `test:docker:live-models` และ `test:docker:live-gateway` รันเฉพาะไฟล์ live ของ profile-key ที่ตรงกันภายในอิมเมจ Docker ของรีโป (`src/agents/models.profiles.live.test.ts` และ `src/gateway/gateway-models.profiles.live.test.ts`) โดยเมานต์ไดเรกทอรี config และ workspace ในเครื่องของคุณ (และ source `~/.profile` หากเมานต์ไว้) entrypoint ในเครื่องที่ตรงกันคือ `test:live:models-profiles` และ `test:live:gateway-profiles` +- Docker live runners ใช้ขีดจำกัดสโมกที่เล็กกว่าเป็นค่าเริ่มต้นเพื่อให้การกวาด Docker ทั้งหมดยังคงใช้งานได้จริง: `test:docker:live-models` มีค่าเริ่มต้นเป็น `OPENCLAW_LIVE_MAX_MODELS=12` และ `test:docker:live-gateway` มีค่าเริ่มต้นเป็น `OPENCLAW_LIVE_GATEWAY_SMOKE=1`, `OPENCLAW_LIVE_GATEWAY_MAX_MODELS=8`, `OPENCLAW_LIVE_GATEWAY_STEP_TIMEOUT_MS=45000` และ - `OPENCLAW_LIVE_GATEWAY_MODEL_TIMEOUT_MS=90000` override env var เหล่านี้เมื่อคุณ - ต้องการสแกนแบบ exhaustive ที่ใหญ่ขึ้นอย่างชัดเจน -- `test:docker:all` สร้างอิมเมจ Docker live หนึ่งครั้งผ่าน `test:docker:live-build`, pack OpenClaw หนึ่งครั้งเป็น npm tarball ผ่าน `scripts/package-openclaw-for-docker.mjs` แล้วสร้าง/ใช้ซ้ำอิมเมจ `scripts/e2e/Dockerfile` สองชุด อิมเมจ bare เป็นเพียง runner Node/Git สำหรับ lane install/update/plugin-dependency; lane เหล่านั้น mount tarball ที่สร้างไว้ล่วงหน้า อิมเมจ functional ติดตั้ง tarball เดียวกันลงใน `/app` สำหรับ lane ฟังก์ชันของแอปที่ build แล้ว คำนิยาม lane ของ Docker อยู่ใน `scripts/lib/docker-e2e-scenarios.mjs`; logic ของ planner อยู่ใน `scripts/lib/docker-e2e-plan.mjs`; `scripts/test-docker-all.mjs` ดำเนินการตาม plan ที่เลือก aggregate ใช้ scheduler ในเครื่องแบบถ่วงน้ำหนัก: `OPENCLAW_DOCKER_ALL_PARALLELISM` ควบคุม process slot ขณะที่ resource cap ป้องกันไม่ให้ lane หนักอย่าง live, npm-install และ multi-service เริ่มพร้อมกันทั้งหมด หาก lane เดียวหนักกว่า cap ที่ active อยู่ scheduler ยังสามารถเริ่มได้เมื่อ pool ว่าง แล้วปล่อยให้รันเพียงตัวเดียวจนกว่าจะมี capacity อีกครั้ง ค่าเริ่มต้นคือ 10 slot, `OPENCLAW_DOCKER_ALL_LIVE_LIMIT=9`, `OPENCLAW_DOCKER_ALL_NPM_LIMIT=10` และ `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT=7`; ปรับ `OPENCLAW_DOCKER_ALL_WEIGHT_LIMIT` หรือ `OPENCLAW_DOCKER_ALL_DOCKER_LIMIT` เฉพาะเมื่อโฮสต์ Docker มี headroom มากขึ้น runner จะทำ Docker preflight เป็นค่าเริ่มต้น, ลบคอนเทนเนอร์ OpenClaw E2E ที่ค้างอยู่, พิมพ์สถานะทุก 30 วินาที, เก็บ timing ของ lane ที่สำเร็จใน `.artifacts/docker-tests/lane-timings.json` และใช้ timing เหล่านั้นเพื่อเริ่ม lane ที่นานกว่าก่อนในการรันภายหลัง ใช้ `OPENCLAW_DOCKER_ALL_DRY_RUN=1` เพื่อพิมพ์ weighted lane manifest โดยไม่ build หรือรัน Docker หรือ `node scripts/test-docker-all.mjs --plan-json` เพื่อพิมพ์แผน CI สำหรับ lane ที่เลือก, ความต้องการ package/image และ credentials -- `Package Acceptance` คือ package gate แบบ native ของ GitHub สำหรับ "tarball ที่ติดตั้งได้นี้ทำงานเป็นผลิตภัณฑ์หรือไม่?" มัน resolve candidate package หนึ่งรายการจาก `source=npm`, `source=ref`, `source=url` หรือ `source=artifact`, อัปโหลดเป็น `package-under-test` แล้วรัน lane Docker E2E ที่ใช้ซ้ำได้กับ tarball นั้นโดยตรง แทนการ repack ref ที่เลือก profile เรียงตามความครอบคลุม: `smoke`, `package`, `product` และ `full` โปรดดู [การทดสอบ updates และ plugins](/th/help/testing-updates-plugins) สำหรับ contract ของ package/update/plugin, matrix survivor ของ published-upgrade, ค่าเริ่มต้นของ release และการ triage ความล้มเหลว -- การตรวจสอบ build และ release รัน `scripts/check-cli-bootstrap-imports.mjs` หลัง tsdown guard จะเดิน static built graph จาก `dist/entry.js` และ `dist/cli/run-main.js` และ fail หาก startup ก่อน dispatch import package dependency เช่น Commander, prompt UI, undici หรือ logging ก่อน command dispatch; มันยังคงควบคุม bundled gateway run chunk ให้อยู่ใน budget และปฏิเสธ static import ของ path gateway ที่ cold ที่รู้จัก smoke ของ CLI แบบ packaged ยังครอบคลุม root help, onboard help, doctor help, status, config schema และคำสั่ง model-list -- ความเข้ากันได้แบบ legacy ของ Package Acceptance ถูกจำกัดสูงสุดที่ `2026.4.25` (รวม `2026.4.25-beta.*`) จนถึง cutoff นั้น harness ยอมรับเฉพาะช่องว่าง metadata ของ shipped-package: รายการ private QA inventory ที่ถูกละไว้, `gateway install --wrapper` ที่หายไป, patch file ที่หายไปใน git fixture ที่มาจาก tarball, `update.channel` ที่ persist หายไป, ตำแหน่ง install-record ของ Plugin แบบ legacy, การ persist marketplace install-record ที่หายไป และการ migrate config metadata ระหว่าง `plugins update` สำหรับ package หลัง `2026.4.25` path เหล่านั้นจะเป็นความล้มเหลวแบบ strict -- Container smoke runners: `test:docker:openwebui`, `test:docker:onboard`, `test:docker:npm-onboard-channel-agent`, `test:docker:update-channel-switch`, `test:docker:upgrade-survivor`, `test:docker:published-upgrade-survivor`, `test:docker:session-runtime-context`, `test:docker:agents-delete-shared-workspace`, `test:docker:gateway-network`, `test:docker:browser-cdp-snapshot`, `test:docker:mcp-channels`, `test:docker:pi-bundle-mcp-tools`, `test:docker:cron-mcp-cleanup`, `test:docker:plugins`, `test:docker:plugin-update`, `test:docker:plugin-lifecycle-matrix` และ `test:docker:config-reload` boot คอนเทนเนอร์จริงหนึ่งตัวหรือมากกว่า และตรวจสอบ path การผสานรวมระดับสูง + `OPENCLAW_LIVE_GATEWAY_MODEL_TIMEOUT_MS=90000` แทนที่ env vars เหล่านั้นเมื่อคุณ + ต้องการการสแกนแบบครบถ้วนที่ใหญ่ขึ้นอย่างชัดเจน +- `test:docker:all` สร้างอิมเมจ Docker live หนึ่งครั้งผ่าน `test:docker:live-build`, แพ็ก OpenClaw หนึ่งครั้งเป็น npm tarball ผ่าน `scripts/package-openclaw-for-docker.mjs` จากนั้นสร้าง/ใช้ซ้ำอิมเมจ `scripts/e2e/Dockerfile` สองรายการ อิมเมจเปล่าเป็นเพียงตัวรัน Node/Git สำหรับ lane การติดตั้ง/อัปเดต/plugin-dependency; lane เหล่านั้นเมานต์ tarball ที่สร้างไว้ล่วงหน้า อิมเมจ functional ติดตั้ง tarball เดียวกันลงใน `/app` สำหรับ lane ฟังก์ชันของแอปที่ build แล้ว นิยาม lane ของ Docker อยู่ใน `scripts/lib/docker-e2e-scenarios.mjs`; ลอจิก planner อยู่ใน `scripts/lib/docker-e2e-plan.mjs`; `scripts/test-docker-all.mjs` ดำเนินการ plan ที่เลือก aggregate ใช้ scheduler ในเครื่องแบบมีน้ำหนัก: `OPENCLAW_DOCKER_ALL_PARALLELISM` ควบคุม process slots ขณะที่ resource caps ป้องกันไม่ให้ lane ที่หนักอย่าง live, npm-install และ multi-service เริ่มพร้อมกันทั้งหมด หาก lane เดียวหนักกว่า caps ที่ใช้งานอยู่ scheduler ยังสามารถเริ่มได้เมื่อ pool ว่าง แล้วปล่อยให้รันลำพังจนกว่าจะมี capacity อีกครั้ง ค่าเริ่มต้นคือ 10 slots, `OPENCLAW_DOCKER_ALL_LIVE_LIMIT=9`, `OPENCLAW_DOCKER_ALL_NPM_LIMIT=10` และ `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT=7`; ปรับ `OPENCLAW_DOCKER_ALL_WEIGHT_LIMIT` หรือ `OPENCLAW_DOCKER_ALL_DOCKER_LIMIT` เฉพาะเมื่อโฮสต์ Docker มี headroom มากขึ้น ตัวรันทำ Docker preflight ตามค่าเริ่มต้น ลบคอนเทนเนอร์ OpenClaw E2E ที่ค้างอยู่ พิมพ์สถานะทุก 30 วินาที เก็บเวลาของ lane ที่สำเร็จใน `.artifacts/docker-tests/lane-timings.json` และใช้เวลาเหล่านั้นเพื่อเริ่ม lane ที่นานกว่าก่อนในการรันครั้งถัดไป ใช้ `OPENCLAW_DOCKER_ALL_DRY_RUN=1` เพื่อพิมพ์ manifest ของ lane แบบมีน้ำหนักโดยไม่ build หรือรัน Docker หรือ `node scripts/test-docker-all.mjs --plan-json` เพื่อพิมพ์ plan ของ CI สำหรับ lane ที่เลือก ความต้องการ package/image และข้อมูลรับรอง +- `Package Acceptance` คือ gate package แบบ GitHub-native สำหรับ “tarball ที่ติดตั้งได้นี้ทำงานเป็นผลิตภัณฑ์ได้หรือไม่?” โดย resolve candidate package หนึ่งรายการจาก `source=npm`, `source=ref`, `source=url` หรือ `source=artifact`, อัปโหลดเป็น `package-under-test` จากนั้นรัน lane Docker E2E ที่นำกลับมาใช้ซ้ำได้กับ tarball นั้นโดยตรงแทนการแพ็ก ref ที่เลือกใหม่ โปรไฟล์เรียงตามความกว้าง: `smoke`, `package`, `product` และ `full` ดู [การทดสอบการอัปเดตและ Plugin](/th/help/testing-updates-plugins) สำหรับสัญญา package/update/plugin, เมทริกซ์ published-upgrade survivor, ค่าเริ่มต้นของ release และการ triage ความล้มเหลว +- การตรวจสอบ build และ release จะรัน `scripts/check-cli-bootstrap-imports.mjs` หลัง tsdown guard จะเดินกราฟ built แบบ static จาก `dist/entry.js` และ `dist/cli/run-main.js` และล้มเหลวหาก startup ก่อน dispatch นำเข้า package dependencies เช่น Commander, prompt UI, undici หรือ logging ก่อน command dispatch; ยังรักษาขนาด chunk การรัน gateway ที่บันเดิลไว้ให้อยู่ภายใต้งบประมาณและปฏิเสธ static imports ของ cold gateway paths ที่รู้จัก สโมก CLI แบบแพ็กเกจยังครอบคลุม root help, onboard help, doctor help, status, config schema และคำสั่ง model-list +- ความเข้ากันได้แบบ legacy ของ Package Acceptance จำกัดไว้ที่ `2026.4.25` (รวม `2026.4.25-beta.*`) จนถึง cutoff นั้น harness จะยอมรับเฉพาะช่องว่าง metadata ของ package ที่เผยแพร่แล้ว: รายการ private QA inventory ที่ถูกละไว้, `gateway install --wrapper` ที่ขาดหาย, ไฟล์ patch ที่ขาดหายใน git fixture ที่ได้จาก tarball, `update.channel` ที่ไม่ถูก persist, ตำแหน่ง install-record ของ Plugin แบบ legacy, การ persist marketplace install-record ที่ขาดหาย และการย้าย config metadata ระหว่าง `plugins update` สำหรับ package หลัง `2026.4.25` path เหล่านั้นเป็นความล้มเหลวที่เข้มงวด +- ตัวรัน container smoke: `test:docker:openwebui`, `test:docker:onboard`, `test:docker:npm-onboard-channel-agent`, `test:docker:update-channel-switch`, `test:docker:upgrade-survivor`, `test:docker:published-upgrade-survivor`, `test:docker:session-runtime-context`, `test:docker:agents-delete-shared-workspace`, `test:docker:gateway-network`, `test:docker:browser-cdp-snapshot`, `test:docker:mcp-channels`, `test:docker:pi-bundle-mcp-tools`, `test:docker:cron-mcp-cleanup`, `test:docker:plugins`, `test:docker:plugin-update`, `test:docker:plugin-lifecycle-matrix` และ `test:docker:config-reload` บูตคอนเทนเนอร์จริงหนึ่งตัวหรือมากกว่า และตรวจสอบ path การผสานรวมระดับสูงกว่า -Live-model Docker runners ยัง bind-mount เฉพาะ CLI auth home ที่จำเป็น (หรือทั้งหมดที่รองรับเมื่อการรันไม่ได้ถูกจำกัดขอบเขต) จากนั้นคัดลอกเข้าไปใน home ของคอนเทนเนอร์ก่อนการรัน เพื่อให้ OAuth ของ external-CLI สามารถ refresh token ได้โดยไม่แก้ไข host auth store: +ตัวรัน Docker ของ live-model ยัง bind-mount เฉพาะ CLI auth homes ที่จำเป็น (หรือทั้งหมดที่รองรับเมื่อการรันไม่ได้ถูกจำกัดขอบเขต) จากนั้นคัดลอกเข้าไปใน home ของคอนเทนเนอร์ก่อนรัน เพื่อให้ OAuth ของ CLI ภายนอกรีเฟรช token ได้โดยไม่กลายพันธุ์ที่เก็บ auth ของโฮสต์: - โมเดลโดยตรง: `pnpm test:docker:live-models` (สคริปต์: `scripts/test-live-models-docker.sh`) -- ACP bind smoke: `pnpm test:docker:live-acp-bind` (สคริปต์: `scripts/test-live-acp-bind-docker.sh`; ครอบคลุม Claude, Codex และ Gemini ตามค่าเริ่มต้น พร้อมความครอบคลุม Droid/OpenCode แบบเข้มงวดผ่าน `pnpm test:docker:live-acp-bind:droid` และ `pnpm test:docker:live-acp-bind:opencode`) -- smoke สำหรับแบ็กเอนด์ CLI: `pnpm test:docker:live-cli-backend` (สคริปต์: `scripts/test-live-cli-backend-docker.sh`) -- smoke สำหรับ Codex app-server harness: `pnpm test:docker:live-codex-harness` (สคริปต์: `scripts/test-live-codex-harness-docker.sh`) +- การทดสอบเบื้องต้นของการ bind ACP: `pnpm test:docker:live-acp-bind` (สคริปต์: `scripts/test-live-acp-bind-docker.sh`; ครอบคลุม Claude, Codex และ Gemini โดยค่าเริ่มต้น พร้อมการครอบคลุม Droid/OpenCode แบบเข้มงวดผ่าน `pnpm test:docker:live-acp-bind:droid` และ `pnpm test:docker:live-acp-bind:opencode`) +- การทดสอบเบื้องต้นของแบ็กเอนด์ CLI: `pnpm test:docker:live-cli-backend` (สคริปต์: `scripts/test-live-cli-backend-docker.sh`) +- การทดสอบเบื้องต้นของ harness สำหรับแอปเซิร์ฟเวอร์ Codex: `pnpm test:docker:live-codex-harness` (สคริปต์: `scripts/test-live-codex-harness-docker.sh`) - Gateway + dev agent: `pnpm test:docker:live-gateway` (สคริปต์: `scripts/test-live-gateway-models-docker.sh`) -- smoke สำหรับการสังเกตการณ์: `pnpm qa:otel:smoke` เป็นเลน QA ส่วนตัวสำหรับซอร์สเช็กเอาต์ โดยตั้งใจไม่รวมอยู่ในเลนแพ็กเกจ Docker release เพราะ npm tarball ละเว้น QA Lab -- smoke สดของ Open WebUI: `pnpm test:docker:openwebui` (สคริปต์: `scripts/e2e/openwebui-docker.sh`) -- วิซาร์ดเริ่มต้นใช้งาน (TTY, การสร้างโครงเต็มรูปแบบ): `pnpm test:docker:onboard` (สคริปต์: `scripts/e2e/onboard-docker.sh`) -- smoke สำหรับการเริ่มต้นใช้งาน/channel/agent ของ Npm tarball: `pnpm test:docker:npm-onboard-channel-agent` ติดตั้ง OpenClaw tarball ที่แพ็กแล้วแบบ global ใน Docker, กำหนดค่า OpenAI ผ่านการเริ่มต้นใช้งานแบบ env-ref พร้อม Telegram ตามค่าเริ่มต้น, รัน doctor และรันหนึ่งรอบของ OpenAI agent แบบจำลอง ใช้ tarball ที่สร้างไว้ล่วงหน้าซ้ำด้วย `OPENCLAW_CURRENT_PACKAGE_TGZ=/path/to/openclaw-*.tgz`, ข้ามการสร้างใหม่บนโฮสต์ด้วย `OPENCLAW_NPM_ONBOARD_HOST_BUILD=0` หรือสลับ channel ด้วย `OPENCLAW_NPM_ONBOARD_CHANNEL=discord` -- smoke สำหรับการสลับ update channel: `pnpm test:docker:update-channel-switch` ติดตั้ง OpenClaw tarball ที่แพ็กแล้วแบบ global ใน Docker, สลับจากแพ็กเกจ `stable` เป็น git `dev`, ตรวจสอบ channel ที่บันทึกคงอยู่และ Plugin ทำงานหลังอัปเดต จากนั้นสลับกลับไปยังแพ็กเกจ `stable` และตรวจสอบสถานะการอัปเดต -- smoke สำหรับ upgrade survivor: `pnpm test:docker:upgrade-survivor` ติดตั้ง OpenClaw tarball ที่แพ็กแล้วทับ fixture ผู้ใช้เก่าแบบ dirty ที่มี agents, การกำหนดค่า channel, plugin allowlists, สถานะ dependency ของ Plugin ที่ล้าสมัย และไฟล์ workspace/session ที่มีอยู่ รันการอัปเดตแพ็กเกจพร้อม doctor แบบไม่โต้ตอบโดยไม่มีคีย์ provider หรือ channel สด จากนั้นเริ่ม Gateway แบบ loopback และตรวจสอบการคงสภาพ config/state รวมถึงงบประมาณ startup/status -- smoke สำหรับ published upgrade survivor: `pnpm test:docker:published-upgrade-survivor` ติดตั้ง `openclaw@latest` ตามค่าเริ่มต้น, seed ไฟล์ผู้ใช้ที่มีอยู่แบบสมจริง, กำหนดค่า baseline นั้นด้วยสูตรคำสั่งที่ฝังไว้, ตรวจสอบ config ที่ได้, อัปเดตการติดตั้งที่เผยแพร่นั้นไปยัง tarball ผู้สมัคร, รัน doctor แบบไม่โต้ตอบ, เขียน `.artifacts/upgrade-survivor/summary.json`, จากนั้นเริ่ม Gateway แบบ loopback และตรวจสอบ intents ที่กำหนดค่าไว้, การคงสภาพ state, startup, `/healthz`, `/readyz` และงบประมาณสถานะ RPC แทนที่ baseline หนึ่งรายการด้วย `OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPEC`, ขอให้ตัวจัดกำหนดการรวมขยาย baseline ที่แน่นอนด้วย `OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPECS` เช่น `all-since-2026.4.23` และขยาย fixtures แบบ issue-shaped ด้วย `OPENCLAW_UPGRADE_SURVIVOR_SCENARIOS` เช่น `reported-issues`; ชุด reported-issues รวม `configured-plugin-installs` สำหรับการซ่อมแซมการติดตั้ง Plugin ภายนอกของ OpenClaw โดยอัตโนมัติ Package Acceptance เปิดเผยค่าเหล่านั้นเป็น `published_upgrade_survivor_baseline`, `published_upgrade_survivor_baselines` และ `published_upgrade_survivor_scenarios` -- smoke สำหรับ session runtime context: `pnpm test:docker:session-runtime-context` ตรวจสอบการคงอยู่ของ transcript บริบท runtime ที่ซ่อนอยู่ รวมถึงการซ่อมแซม doctor สำหรับสาขา prompt-rewrite ที่ซ้ำกันซึ่งได้รับผลกระทบ -- smoke สำหรับการติดตั้ง Bun แบบ global: `bash scripts/e2e/bun-global-install-smoke.sh` แพ็ก tree ปัจจุบัน, ติดตั้งด้วย `bun install -g` ใน home ที่แยกไว้ และตรวจสอบว่า `openclaw infer image providers --json` ส่งคืน provider รูปภาพที่บันเดิลมาแทนที่จะค้าง ใช้ tarball ที่สร้างไว้ล่วงหน้าซ้ำด้วย `OPENCLAW_BUN_GLOBAL_SMOKE_PACKAGE_TGZ=/path/to/openclaw-*.tgz`, ข้าม host build ด้วย `OPENCLAW_BUN_GLOBAL_SMOKE_HOST_BUILD=0` หรือคัดลอก `dist/` จากอิมเมจ Docker ที่สร้างแล้วด้วย `OPENCLAW_BUN_GLOBAL_SMOKE_DIST_IMAGE=openclaw-dockerfile-smoke:local` -- smoke สำหรับ Installer Docker: `bash scripts/test-install-sh-docker.sh` แชร์ npm cache หนึ่งชุดระหว่างคอนเทนเนอร์ root, update และ direct-npm ของมัน smoke การอัปเดตใช้ npm `latest` เป็น stable baseline ตามค่าเริ่มต้นก่อนอัปเกรดไปยัง tarball ผู้สมัคร แทนที่ด้วย `OPENCLAW_INSTALL_SMOKE_UPDATE_BASELINE=2026.4.22` ในเครื่อง หรือด้วยอินพุต `update_baseline_version` ของเวิร์กโฟลว์ Install Smoke บน GitHub การตรวจสอบ installer แบบ non-root ใช้ npm cache ที่แยกไว้เพื่อให้รายการ cache ที่ root เป็นเจ้าของไม่บดบังพฤติกรรมการติดตั้งแบบ user-local ตั้งค่า `OPENCLAW_INSTALL_SMOKE_NPM_CACHE_DIR=/path/to/cache` เพื่อใช้ cache root/update/direct-npm ซ้ำระหว่างการรันในเครื่องซ้ำ -- Install Smoke CI ข้ามการอัปเดต direct-npm global ที่ซ้ำด้วย `OPENCLAW_INSTALL_SMOKE_SKIP_NPM_GLOBAL=1`; รันสคริปต์ในเครื่องโดยไม่มี env นั้นเมื่อจำเป็นต้องครอบคลุม `npm install -g` โดยตรง -- smoke สำหรับ CLI ลบ workspace ที่ใช้ร่วมกันของ Agents: `pnpm test:docker:agents-delete-shared-workspace` (สคริปต์: `scripts/e2e/agents-delete-shared-workspace-docker.sh`) สร้างอิมเมจ Dockerfile ระดับ root ตามค่าเริ่มต้น, seed agents สองตัวที่มี workspace หนึ่งรายการใน container home ที่แยกไว้, รัน `agents delete --json` และตรวจสอบ JSON ที่ถูกต้องพร้อมพฤติกรรมการคง workspace ไว้ ใช้อิมเมจ install-smoke ซ้ำด้วย `OPENCLAW_AGENTS_DELETE_SHARED_WORKSPACE_E2E_IMAGE=openclaw-dockerfile-smoke:local OPENCLAW_AGENTS_DELETE_SHARED_WORKSPACE_E2E_SKIP_BUILD=1` -- เครือข่าย Gateway (สองคอนเทนเนอร์, WS auth + health): `pnpm test:docker:gateway-network` (สคริปต์: `scripts/e2e/gateway-network-docker.sh`) -- smoke สำหรับ snapshot ของ Browser CDP: `pnpm test:docker:browser-cdp-snapshot` (สคริปต์: `scripts/e2e/browser-cdp-snapshot-docker.sh`) สร้างอิมเมจ source E2E พร้อมเลเยอร์ Chromium, เริ่ม Chromium ด้วย CDP ดิบ, รัน `browser doctor --deep` และตรวจสอบว่า snapshot ของบทบาท CDP ครอบคลุม URL ของลิงก์, clickable ที่เลื่อนระดับจาก cursor, iframe refs และ frame metadata -- regression สำหรับ OpenAI Responses web_search minimal reasoning: `pnpm test:docker:openai-web-search-minimal` (สคริปต์: `scripts/e2e/openai-web-search-minimal-docker.sh`) รันเซิร์ฟเวอร์ OpenAI แบบจำลองผ่าน Gateway, ตรวจสอบว่า `web_search` ยกระดับ `reasoning.effort` จาก `minimal` เป็น `low`, จากนั้นบังคับให้ schema ของ provider ปฏิเสธและตรวจสอบว่ารายละเอียดดิบปรากฏในบันทึก Gateway -- MCP channel bridge (Gateway ที่ seed แล้ว + stdio bridge + smoke สำหรับ raw Claude notification-frame): `pnpm test:docker:mcp-channels` (สคริปต์: `scripts/e2e/mcp-channels-docker.sh`) -- เครื่องมือ MCP ในบันเดิล Pi (เซิร์ฟเวอร์ MCP stdio จริง + smoke สำหรับโปรไฟล์ Pi แบบฝังที่ allow/deny): `pnpm test:docker:pi-bundle-mcp-tools` (สคริปต์: `scripts/e2e/pi-bundle-mcp-tools-docker.sh`) -- การล้างข้อมูล Cron/subagent MCP (Gateway จริง + การรื้อถอน child stdio MCP หลังจากรัน cron แบบแยกและ subagent แบบ one-shot): `pnpm test:docker:cron-mcp-cleanup` (สคริปต์: `scripts/e2e/cron-mcp-cleanup-docker.sh`) -- Plugins (smoke สำหรับติดตั้ง/อัปเดตสำหรับ local path, `file:`, npm registry ที่มี dependency แบบ hoisted, git moving refs, ClawHub kitchen-sink, marketplace updates และการเปิดใช้/ตรวจสอบ Claude-bundle): `pnpm test:docker:plugins` (สคริปต์: `scripts/e2e/plugins-docker.sh`) - ตั้งค่า `OPENCLAW_PLUGINS_E2E_CLAWHUB=0` เพื่อข้ามบล็อก ClawHub หรือแทนที่คู่แพ็กเกจ/runtime kitchen-sink เริ่มต้นด้วย `OPENCLAW_PLUGINS_E2E_CLAWHUB_SPEC` และ `OPENCLAW_PLUGINS_E2E_CLAWHUB_ID` หากไม่มี `OPENCLAW_CLAWHUB_URL`/`CLAWHUB_URL` การทดสอบจะใช้เซิร์ฟเวอร์ fixture ClawHub ในเครื่องแบบปิดครบ -- smoke สำหรับการอัปเดต Plugin ที่ไม่เปลี่ยนแปลง: `pnpm test:docker:plugin-update` (สคริปต์: `scripts/e2e/plugin-update-unchanged-docker.sh`) -- smoke สำหรับเมทริกซ์วงจรชีวิต Plugin: `pnpm test:docker:plugin-lifecycle-matrix` ติดตั้ง OpenClaw tarball ที่แพ็กแล้วในคอนเทนเนอร์เปล่า, ติดตั้ง npm plugin, สลับเปิด/ปิด, อัปเกรดและดาวน์เกรดผ่าน npm registry ในเครื่อง, ลบโค้ดที่ติดตั้งแล้ว จากนั้นตรวจสอบว่า uninstall ยังลบ state ที่ล้าสมัยได้ พร้อมบันทึกเมตริก RSS/CPU สำหรับแต่ละช่วงของวงจรชีวิต -- smoke สำหรับ metadata reload ของ config: `pnpm test:docker:config-reload` (สคริปต์: `scripts/e2e/config-reload-source-docker.sh`) -- Plugins: `pnpm test:docker:plugins` ครอบคลุม smoke สำหรับติดตั้ง/อัปเดตสำหรับ local path, `file:`, npm registry ที่มี dependency แบบ hoisted, git moving refs, fixtures ของ ClawHub, marketplace updates และการเปิดใช้/ตรวจสอบ Claude-bundle `pnpm test:docker:plugin-update` ครอบคลุมพฤติกรรมการอัปเดตที่ไม่เปลี่ยนแปลงสำหรับ Plugins ที่ติดตั้งแล้ว `pnpm test:docker:plugin-lifecycle-matrix` ครอบคลุมการติดตั้ง npm plugin แบบติดตามทรัพยากร, เปิดใช้, ปิดใช้, อัปเกรด, ดาวน์เกรด และถอนการติดตั้งเมื่อโค้ดหายไป +- การทดสอบเบื้องต้นด้าน observability: `pnpm qa:otel:smoke` เป็นเลนตรวจซอร์สแบบ private QA จาก checkout โดยตั้งใจไม่รวมอยู่ในเลน Docker release ของแพ็กเกจ เพราะ npm tarball ไม่รวม QA Lab +- การทดสอบเบื้องต้นแบบ live ของ Open WebUI: `pnpm test:docker:openwebui` (สคริปต์: `scripts/e2e/openwebui-docker.sh`) +- วิซาร์ด onboarding (TTY, การสร้างโครงครบถ้วน): `pnpm test:docker:onboard` (สคริปต์: `scripts/e2e/onboard-docker.sh`) +- การทดสอบเบื้องต้นของ onboarding/channel/agent สำหรับ npm tarball: `pnpm test:docker:npm-onboard-channel-agent` ติดตั้ง OpenClaw tarball ที่แพ็กแล้วแบบ global ใน Docker, ตั้งค่า OpenAI ผ่าน env-ref onboarding พร้อม Telegram โดยค่าเริ่มต้น, รัน doctor และรัน agent turn ของ OpenAI แบบ mock หนึ่งครั้ง ใช้ tarball ที่สร้างไว้ล่วงหน้าซ้ำด้วย `OPENCLAW_CURRENT_PACKAGE_TGZ=/path/to/openclaw-*.tgz`, ข้ามการ build บนโฮสต์ด้วย `OPENCLAW_NPM_ONBOARD_HOST_BUILD=0` หรือเปลี่ยน channel ด้วย `OPENCLAW_NPM_ONBOARD_CHANNEL=discord` +- การทดสอบเบื้องต้นของการสลับ update channel: `pnpm test:docker:update-channel-switch` ติดตั้ง OpenClaw tarball ที่แพ็กแล้วแบบ global ใน Docker, สลับจากแพ็กเกจ `stable` ไปยัง git `dev`, ตรวจสอบ channel ที่คงค่าไว้และงานหลังอัปเดตของ Plugin แล้วสลับกลับไปยังแพ็กเกจ `stable` และตรวจสถานะอัปเดต +- การทดสอบเบื้องต้นของ upgrade survivor: `pnpm test:docker:upgrade-survivor` ติดตั้ง OpenClaw tarball ที่แพ็กแล้วทับ fixture ผู้ใช้เก่าแบบ dirty ที่มี agents, การตั้งค่า channel, allowlists ของ Plugin, สถานะ dependency ของ Plugin ที่ค้าง, และไฟล์ workspace/session ที่มีอยู่ รัน package update พร้อม doctor แบบ non-interactive โดยไม่มี live provider หรือคีย์ channel จากนั้นเริ่ม Gateway แบบ loopback และตรวจการคงค่าของ config/state รวมถึงงบประมาณ startup/status +- การทดสอบเบื้องต้นของ published upgrade survivor: `pnpm test:docker:published-upgrade-survivor` ติดตั้ง `openclaw@latest` โดยค่าเริ่มต้น, seed ไฟล์ existing-user ที่สมจริง, ตั้งค่า baseline นั้นด้วย command recipe ที่ฝังไว้, ตรวจสอบ config ที่ได้, อัปเดตการติดตั้ง published นั้นไปยัง candidate tarball, รัน doctor แบบ non-interactive, เขียน `.artifacts/upgrade-survivor/summary.json`, จากนั้นเริ่ม Gateway แบบ loopback และตรวจ configured intents, การคงค่า state, startup, `/healthz`, `/readyz` และงบประมาณสถานะ RPC Override baseline เดียวด้วย `OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPEC`, ขอให้ aggregate scheduler ขยาย baseline แบบ exact ด้วย `OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPECS` เช่น `all-since-2026.4.23`, และขยาย fixture รูปแบบ issue ด้วย `OPENCLAW_UPGRADE_SURVIVOR_SCENARIOS` เช่น `reported-issues`; ชุด reported-issues รวม `configured-plugin-installs` สำหรับการซ่อมแซมการติดตั้ง Plugin ภายนอกของ OpenClaw แบบอัตโนมัติ Package Acceptance เปิดเผยค่าเหล่านั้นเป็น `published_upgrade_survivor_baseline`, `published_upgrade_survivor_baselines` และ `published_upgrade_survivor_scenarios` +- การทดสอบเบื้องต้นของ session runtime context: `pnpm test:docker:session-runtime-context` ตรวจสอบการคงอยู่ของ transcript ของ hidden runtime context พร้อมการซ่อมแซมด้วย doctor สำหรับ branch prompt-rewrite ที่ซ้ำกันและได้รับผลกระทบ +- การทดสอบเบื้องต้นของการติดตั้ง Bun แบบ global: `bash scripts/e2e/bun-global-install-smoke.sh` แพ็ก tree ปัจจุบัน, ติดตั้งด้วย `bun install -g` ใน home ที่แยกไว้ และตรวจสอบว่า `openclaw infer image providers --json` คืน image providers ที่ bundled แทนที่จะค้าง ใช้ tarball ที่สร้างไว้ล่วงหน้าซ้ำด้วย `OPENCLAW_BUN_GLOBAL_SMOKE_PACKAGE_TGZ=/path/to/openclaw-*.tgz`, ข้ามการ build บนโฮสต์ด้วย `OPENCLAW_BUN_GLOBAL_SMOKE_HOST_BUILD=0` หรือคัดลอก `dist/` จาก Docker image ที่ build แล้วด้วย `OPENCLAW_BUN_GLOBAL_SMOKE_DIST_IMAGE=openclaw-dockerfile-smoke:local` +- การทดสอบเบื้องต้นของ Installer Docker: `bash scripts/test-install-sh-docker.sh` ใช้ npm cache เดียวร่วมกันระหว่าง root, update และ direct-npm containers การทดสอบเบื้องต้นของ update ใช้ npm `latest` เป็น baseline stable โดยค่าเริ่มต้นก่อนอัปเกรดเป็น candidate tarball Override ด้วย `OPENCLAW_INSTALL_SMOKE_UPDATE_BASELINE=2026.4.22` แบบ local หรือด้วย input `update_baseline_version` ของ Install Smoke workflow บน GitHub การตรวจ installer แบบ non-root เก็บ npm cache ที่แยกไว้ เพื่อไม่ให้รายการ cache ที่ root เป็นเจ้าของบดบังพฤติกรรมการติดตั้งแบบ user-local ตั้งค่า `OPENCLAW_INSTALL_SMOKE_NPM_CACHE_DIR=/path/to/cache` เพื่อใช้ cache root/update/direct-npm ซ้ำในการรัน local ซ้ำ +- Install Smoke CI ข้ามการอัปเดต direct-npm global ที่ซ้ำด้วย `OPENCLAW_INSTALL_SMOKE_SKIP_NPM_GLOBAL=1`; รันสคริปต์แบบ local โดยไม่มี env นั้นเมื่อจำเป็นต้องมีการครอบคลุม `npm install -g` โดยตรง +- การทดสอบเบื้องต้นของ CLI สำหรับ agents delete shared workspace: `pnpm test:docker:agents-delete-shared-workspace` (สคริปต์: `scripts/e2e/agents-delete-shared-workspace-docker.sh`) build image จาก Dockerfile รากโดยค่าเริ่มต้น, seed agents สองตัวพร้อม workspace หนึ่งรายการใน container home ที่แยกไว้, รัน `agents delete --json` และตรวจสอบ JSON ที่ถูกต้องพร้อมพฤติกรรมการคง workspace ไว้ ใช้ install-smoke image ซ้ำด้วย `OPENCLAW_AGENTS_DELETE_SHARED_WORKSPACE_E2E_IMAGE=openclaw-dockerfile-smoke:local OPENCLAW_AGENTS_DELETE_SHARED_WORKSPACE_E2E_SKIP_BUILD=1` +- Gateway networking (สอง containers, WS auth + health): `pnpm test:docker:gateway-network` (สคริปต์: `scripts/e2e/gateway-network-docker.sh`) +- การทดสอบเบื้องต้นของ Browser CDP snapshot: `pnpm test:docker:browser-cdp-snapshot` (สคริปต์: `scripts/e2e/browser-cdp-snapshot-docker.sh`) build source E2E image พร้อมเลเยอร์ Chromium, เริ่ม Chromium ด้วย raw CDP, รัน `browser doctor --deep` และตรวจสอบว่า CDP role snapshots ครอบคลุม link URLs, clickables ที่ cursor-promoted, iframe refs และ frame metadata +- การถดถอยของ minimal reasoning สำหรับ OpenAI Responses web_search: `pnpm test:docker:openai-web-search-minimal` (สคริปต์: `scripts/e2e/openai-web-search-minimal-docker.sh`) รันเซิร์ฟเวอร์ OpenAI แบบ mock ผ่าน Gateway, ตรวจสอบว่า `web_search` ยกระดับ `reasoning.effort` จาก `minimal` เป็น `low`, จากนั้นบังคับให้ provider schema ปฏิเสธและตรวจว่ารายละเอียดดิบปรากฏใน Gateway logs +- MCP channel bridge (seeded Gateway + stdio bridge + การทดสอบเบื้องต้นของ raw Claude notification-frame): `pnpm test:docker:mcp-channels` (สคริปต์: `scripts/e2e/mcp-channels-docker.sh`) +- เครื่องมือ MCP ของ Pi bundle (เซิร์ฟเวอร์ stdio MCP จริง + การทดสอบเบื้องต้นของ allow/deny สำหรับ embedded Pi profile): `pnpm test:docker:pi-bundle-mcp-tools` (สคริปต์: `scripts/e2e/pi-bundle-mcp-tools-docker.sh`) +- การ cleanup MCP ของ Cron/subagent (Gateway จริง + การ teardown ของ stdio MCP child หลังการรัน cron แบบแยกและ one-shot subagent): `pnpm test:docker:cron-mcp-cleanup` (สคริปต์: `scripts/e2e/cron-mcp-cleanup-docker.sh`) +- Plugins (การทดสอบเบื้องต้นของการติดตั้ง/อัปเดตสำหรับ local path, `file:`, npm registry ที่มี hoisted dependencies, git moving refs, ClawHub kitchen-sink, marketplace updates และการ enable/inspect Claude-bundle): `pnpm test:docker:plugins` (สคริปต์: `scripts/e2e/plugins-docker.sh`) + ตั้งค่า `OPENCLAW_PLUGINS_E2E_CLAWHUB=0` เพื่อข้ามบล็อก ClawHub หรือ override คู่ package/runtime kitchen-sink ค่าเริ่มต้นด้วย `OPENCLAW_PLUGINS_E2E_CLAWHUB_SPEC` และ `OPENCLAW_PLUGINS_E2E_CLAWHUB_ID` หากไม่มี `OPENCLAW_CLAWHUB_URL`/`CLAWHUB_URL` การทดสอบจะใช้เซิร์ฟเวอร์ fixture ClawHub แบบ local ที่ปิดล้อม +- การทดสอบเบื้องต้นของ Plugin update unchanged: `pnpm test:docker:plugin-update` (สคริปต์: `scripts/e2e/plugin-update-unchanged-docker.sh`) +- การทดสอบเบื้องต้นของ Plugin lifecycle matrix: `pnpm test:docker:plugin-lifecycle-matrix` ติดตั้ง OpenClaw tarball ที่แพ็กแล้วใน container เปล่า, ติดตั้ง npm Plugin, toggle enable/disable, อัปเกรดและดาวน์เกรดผ่าน npm registry แบบ local, ลบโค้ดที่ติดตั้งแล้ว จากนั้นตรวจสอบว่า uninstall ยังลบสถานะค้างได้ พร้อมบันทึกเมตริก RSS/CPU สำหรับแต่ละช่วง lifecycle +- การทดสอบเบื้องต้นของ config reload metadata: `pnpm test:docker:config-reload` (สคริปต์: `scripts/e2e/config-reload-source-docker.sh`) +- Plugins: `pnpm test:docker:plugins` ครอบคลุมการทดสอบเบื้องต้นของ install/update สำหรับ local path, `file:`, npm registry ที่มี hoisted dependencies, git moving refs, ClawHub fixtures, marketplace updates และการ enable/inspect Claude-bundle `pnpm test:docker:plugin-update` ครอบคลุมพฤติกรรม update unchanged สำหรับ Plugins ที่ติดตั้งแล้ว `pnpm test:docker:plugin-lifecycle-matrix` ครอบคลุมการ install, enable, disable, upgrade, downgrade และ missing-code uninstall ของ npm Plugin พร้อมติดตามทรัพยากร -หากต้องการสร้างอิมเมจ functional ที่ใช้ร่วมกันล่วงหน้าและนำมาใช้ซ้ำด้วยตนเอง: +เพื่อ prebuild และใช้ image functional ที่ใช้ร่วมกันซ้ำแบบ manual: ```bash OPENCLAW_DOCKER_E2E_IMAGE=openclaw-docker-e2e-functional:local pnpm test:docker:e2e-build OPENCLAW_DOCKER_E2E_IMAGE=openclaw-docker-e2e-functional:local OPENCLAW_SKIP_DOCKER_BUILD=1 pnpm test:docker:mcp-channels ``` -การแทนที่อิมเมจเฉพาะ suite เช่น `OPENCLAW_GATEWAY_NETWORK_E2E_IMAGE` ยังคงมีผลเหนือกว่าเมื่อกำหนดไว้ เมื่อ `OPENCLAW_SKIP_DOCKER_BUILD=1` ชี้ไปยังอิมเมจ shared ระยะไกล สคริปต์จะ pull อิมเมจนั้นหากยังไม่มีในเครื่อง การทดสอบ Docker สำหรับ QR และ installer เก็บ Dockerfile ของตัวเองไว้ เพราะตรวจสอบพฤติกรรมแพ็กเกจ/การติดตั้ง แทนที่จะเป็น runtime ของแอปที่สร้างร่วมกัน +image override เฉพาะ suite เช่น `OPENCLAW_GATEWAY_NETWORK_E2E_IMAGE` ยังคงมีผลเหนือกว่าเมื่อถูกตั้งค่า เมื่อ `OPENCLAW_SKIP_DOCKER_BUILD=1` ชี้ไปยัง image shared ระยะไกล สคริปต์จะ pull ถ้ายังไม่มีในเครื่อง การทดสอบ Docker สำหรับ QR และ installer เก็บ Dockerfiles ของตัวเองไว้ เพราะตรวจสอบพฤติกรรม package/install แทนที่จะตรวจ runtime ของแอปที่ build แล้วแบบ shared -ตัวรัน Docker สำหรับโมเดลแบบสดยัง bind-mount checkout ปัจจุบันแบบอ่านอย่างเดียว และ -stage ลงใน workdir ชั่วคราวภายในคอนเทนเนอร์ด้วย วิธีนี้ช่วยให้ runtime -image มีขนาดเล็ก แต่ยังคงรัน Vitest กับซอร์ส/คอนฟิกในเครื่องของคุณได้ตรงตัว -ขั้นตอน staging จะข้ามแคชขนาดใหญ่ที่มีเฉพาะในเครื่องและเอาต์พุต build ของแอป เช่น -`.pnpm-store`, `.worktrees`, `__openclaw_vitest__` และไดเรกทอรีเอาต์พุต `.build` ในเครื่องแอปหรือ -Gradle เพื่อให้การรัน Docker แบบสดไม่เสียเวลาหลายนาทีในการคัดลอก +ตัวรัน Docker สำหรับ live-model จะ bind-mount checkout ปัจจุบันแบบอ่านอย่างเดียวด้วย และ +จัดวางลงใน workdir ชั่วคราวภายในคอนเทนเนอร์ วิธีนี้ทำให้อิมเมจ runtime +มีขนาดเล็ก ขณะที่ยังคงรัน Vitest กับซอร์ส/คอนฟิกในเครื่องของคุณอย่างตรงตัว +ขั้นตอนการจัดวางจะข้ามแคชขนาดใหญ่ที่ใช้เฉพาะในเครื่องและเอาต์พุตบิลด์ของแอป เช่น +`.pnpm-store`, `.worktrees`, `__openclaw_vitest__` และไดเรกทอรีเอาต์พุต `.build` ของแอปในเครื่องหรือ +Gradle เพื่อให้การรัน Docker แบบ live ไม่ต้องใช้เวลาหลายนาทีในการคัดลอก อาร์ติแฟกต์เฉพาะเครื่อง -ตัวรันเหล่านี้ยังกำหนด `OPENCLAW_SKIP_CHANNELS=1` เพื่อให้ probe สดของ gateway ไม่เริ่ม -worker ของช่องทางจริง เช่น Telegram/Discord/ฯลฯ ภายในคอนเทนเนอร์ +ขั้นตอนเหล่านี้ยังกำหนด `OPENCLAW_SKIP_CHANNELS=1` เพื่อให้โพรบ live ของ Gateway ไม่เริ่ม +เวิร์กเกอร์ช่องทาง Telegram/Discord/ฯลฯ จริงภายในคอนเทนเนอร์ `test:docker:live-models` ยังคงรัน `pnpm test:live` ดังนั้นให้ส่งผ่าน -`OPENCLAW_LIVE_GATEWAY_*` ด้วยเมื่อคุณต้องการจำกัดหรือยกเว้น coverage สดของ gateway -จาก lane Docker นั้น -`test:docker:openwebui` เป็น smoke ความเข้ากันได้ระดับสูงกว่า: จะเริ่ม -คอนเทนเนอร์ OpenClaw gateway โดยเปิด endpoint HTTP ที่เข้ากันได้กับ OpenAI, -เริ่มคอนเทนเนอร์ Open WebUI ที่ pin ไว้ให้เชื่อมกับ gateway นั้น, ลงชื่อเข้าใช้ผ่าน -Open WebUI, ตรวจสอบว่า `/api/models` เปิดเผย `openclaw/default` แล้วส่ง -คำขอแชตจริงผ่านพร็อกซี `/api/chat/completions` ของ Open WebUI -การรันครั้งแรกอาจช้าลงอย่างเห็นได้ชัด เพราะ Docker อาจต้อง pull image ของ -Open WebUI และ Open WebUI อาจต้องทำขั้นตอน cold-start ของตัวเองให้เสร็จ -lane นี้คาดหวัง key ของโมเดลสดที่ใช้งานได้ และ `OPENCLAW_PROFILE_FILE` -(`~/.profile` โดยค่าเริ่มต้น) เป็นวิธีหลักในการจัดหา key นั้นในการรันแบบ Docker +`OPENCLAW_LIVE_GATEWAY_*` ด้วยเมื่อคุณต้องการจำกัดหรือยกเว้นการครอบคลุม live ของ Gateway +จากเลน Docker นั้น +`test:docker:openwebui` เป็น smoke ความเข้ากันได้ระดับสูงกว่า: มันเริ่มคอนเทนเนอร์ +Gateway ของ OpenClaw โดยเปิดใช้งาน endpoint HTTP ที่เข้ากันได้กับ OpenAI, +เริ่มคอนเทนเนอร์ Open WebUI ที่ pin ไว้กับ Gateway นั้น, ลงชื่อเข้าใช้ผ่าน +Open WebUI, ตรวจสอบว่า `/api/models` เปิดเผย `openclaw/default` จากนั้นส่ง +คำขอแชทจริงผ่านพร็อกซี `/api/chat/completions` ของ Open WebUI +การรันครั้งแรกอาจช้ากว่าอย่างเห็นได้ชัด เพราะ Docker อาจต้องดึงอิมเมจ +Open WebUI และ Open WebUI อาจต้องตั้งค่า cold-start ของตัวเองให้เสร็จก่อน +เลนนี้คาดหวังคีย์โมเดล live ที่ใช้งานได้ และ `OPENCLAW_PROFILE_FILE` +(`~/.profile` โดยค่าเริ่มต้น) เป็นวิธีหลักในการจัดเตรียมคีย์นั้นในการรันแบบ Dockerized การรันที่สำเร็จจะพิมพ์ payload JSON ขนาดเล็ก เช่น `{ "ok": true, "model": "openclaw/default", ... }` -`test:docker:mcp-channels` ตั้งใจให้ deterministic และไม่ต้องใช้บัญชี -Telegram, Discord หรือ iMessage จริง โดยจะบูตคอนเทนเนอร์ Gateway ที่ seed ไว้ -เริ่มคอนเทนเนอร์ที่สองซึ่ง spawn `openclaw mcp serve` แล้ว -ตรวจสอบการค้นพบบทสนทนาที่ถูก route, การอ่าน transcript, metadata ของ attachment, -พฤติกรรมคิว event สด, routing การส่งออกขาออก และการแจ้งเตือน channel + -permission แบบ Claude ผ่านสะพาน stdio MCP จริง การตรวจสอบการแจ้งเตือน -จะตรวจ frame stdio MCP ดิบโดยตรง เพื่อให้ smoke ตรวจสอบสิ่งที่ -สะพานปล่อยออกมาจริง ไม่ใช่แค่สิ่งที่ client SDK เฉพาะตัวหนึ่งบังเอิญ expose -`test:docker:pi-bundle-mcp-tools` เป็น deterministic และไม่ต้องใช้ key ของโมเดลสด -โดยจะ build image Docker ของ repo, เริ่มเซิร์ฟเวอร์ probe stdio MCP จริง -ภายในคอนเทนเนอร์, materialize เซิร์ฟเวอร์นั้นผ่าน runtime MCP ของ bundle Pi ที่ฝังอยู่, -เรียกใช้ tool แล้วตรวจสอบว่า `coding` และ `messaging` ยังคงเก็บ -tool `bundle-mcp` ไว้ ขณะที่ `minimal` และ `tools.deny: ["bundle-mcp"]` กรองออก -`test:docker:cron-mcp-cleanup` เป็น deterministic และไม่ต้องใช้ key ของโมเดลสด -โดยจะเริ่ม Gateway ที่ seed ไว้พร้อมเซิร์ฟเวอร์ probe stdio MCP จริง, รัน -turn cron แบบ isolated และ turn ลูกแบบ one-shot ของ `/subagents spawn` แล้วตรวจสอบว่า -process ลูก MCP ออกหลังจากแต่ละรัน +`test:docker:mcp-channels` ถูกออกแบบให้กำหนดผลลัพธ์ได้แน่นอนและไม่ต้องใช้ +บัญชี Telegram, Discord หรือ iMessage จริง มันบูตคอนเทนเนอร์ Gateway +ที่ seed ไว้, เริ่มคอนเทนเนอร์ที่สองที่ spawn `openclaw mcp serve`, จากนั้น +ตรวจสอบการค้นหาบทสนทนาที่ถูก route, การอ่าน transcript, เมตาดาต้าไฟล์แนบ, +พฤติกรรมคิวอีเวนต์ live, การ route การส่งออก, และการแจ้งเตือนช่องทางแบบ Claude + +สิทธิ์ผ่าน stdio MCP bridge จริง การตรวจสอบการแจ้งเตือนจะตรวจดูเฟรม stdio MCP ดิบ +โดยตรง เพื่อให้ smoke ตรวจสอบสิ่งที่ bridge ส่งออกจริง ไม่ใช่แค่สิ่งที่ SDK ไคลเอนต์เฉพาะตัวหนึ่งแสดงขึ้นมา +`test:docker:pi-bundle-mcp-tools` ถูกกำหนดผลลัพธ์ได้แน่นอนและไม่ต้องใช้คีย์โมเดล live +มันบิลด์อิมเมจ Docker ของ repo, เริ่มเซิร์ฟเวอร์โพรบ stdio MCP จริง +ภายในคอนเทนเนอร์, materialize เซิร์ฟเวอร์นั้นผ่าน runtime MCP ของ Pi bundle +ที่ฝังมา, เรียกใช้เครื่องมือ, จากนั้นตรวจสอบว่า `coding` และ `messaging` ยังคง +เครื่องมือ `bundle-mcp` ไว้ ขณะที่ `minimal` และ `tools.deny: ["bundle-mcp"]` กรองเครื่องมือเหล่านั้นออก +`test:docker:cron-mcp-cleanup` ถูกกำหนดผลลัพธ์ได้แน่นอนและไม่ต้องใช้คีย์โมเดล live +มันเริ่ม Gateway ที่ seed ไว้พร้อมเซิร์ฟเวอร์โพรบ stdio MCP จริง, รัน +turn ของ cron แบบแยกโดดเดี่ยวและ turn ลูกแบบ one-shot ของ `/subagents spawn`, จากนั้นตรวจสอบว่า +โปรเซสลูก MCP ออกหลังจากการรันแต่ละครั้ง -Smoke เธรด ACP ภาษาธรรมดาแบบแมนนวล (ไม่ใช่ CI): +Smoke thread ภาษาธรรมดาของ ACP แบบแมนนวล (ไม่ใช่ CI): - `bun scripts/dev/discord-acp-plain-language-smoke.ts --channel ...` -- เก็บสคริปต์นี้ไว้สำหรับ workflow การ regression/debug อาจต้องใช้ซ้ำอีกสำหรับการตรวจสอบ routing เธรด ACP ดังนั้นอย่าลบ +- เก็บสคริปต์นี้ไว้สำหรับเวิร์กโฟลว์ regression/debug อาจจำเป็นต้องใช้อีกครั้งสำหรับการตรวจสอบการ route thread ของ ACP ดังนั้นอย่าลบทิ้ง ตัวแปร env ที่มีประโยชน์: - `OPENCLAW_CONFIG_DIR=...` (ค่าเริ่มต้น: `~/.openclaw`) mount ไปที่ `/home/node/.openclaw` - `OPENCLAW_WORKSPACE_DIR=...` (ค่าเริ่มต้น: `~/.openclaw/workspace`) mount ไปที่ `/home/node/.openclaw/workspace` -- `OPENCLAW_PROFILE_FILE=...` (ค่าเริ่มต้น: `~/.profile`) mount ไปที่ `/home/node/.profile` และ source ก่อนรันการทดสอบ -- `OPENCLAW_DOCKER_PROFILE_ENV_ONLY=1` เพื่อตรวจสอบเฉพาะตัวแปร env ที่ source จาก `OPENCLAW_PROFILE_FILE` โดยใช้ไดเรกทอรี config/workspace ชั่วคราวและไม่มี mount auth ของ CLI ภายนอก +- `OPENCLAW_PROFILE_FILE=...` (ค่าเริ่มต้น: `~/.profile`) mount ไปที่ `/home/node/.profile` และ source ก่อนรันเทสต์ +- `OPENCLAW_DOCKER_PROFILE_ENV_ONLY=1` เพื่อตรวจสอบเฉพาะตัวแปร env ที่ source จาก `OPENCLAW_PROFILE_FILE` โดยใช้ไดเรกทอรี config/workspace ชั่วคราวและไม่มีการ mount auth ของ CLI ภายนอก - `OPENCLAW_DOCKER_CLI_TOOLS_DIR=...` (ค่าเริ่มต้น: `~/.cache/openclaw/docker-cli-tools`) mount ไปที่ `/home/node/.npm-global` สำหรับการติดตั้ง CLI ที่แคชไว้ภายใน Docker -- ไดเรกทอรี/ไฟล์ auth ของ CLI ภายนอกใต้ `$HOME` จะถูก mount แบบอ่านอย่างเดียวใต้ `/host-auth...` แล้วคัดลอกไปยัง `/home/node/...` ก่อนเริ่มการทดสอบ - - ไดเรกทอรีเริ่มต้น: `.minimax` - - ไฟล์เริ่มต้น: `~/.codex/auth.json`, `~/.codex/config.toml`, `.claude.json`, `~/.claude/.credentials.json`, `~/.claude/settings.json`, `~/.claude/settings.local.json` - - การรัน provider แบบจำกัดจะ mount เฉพาะไดเรกทอรี/ไฟล์ที่จำเป็นซึ่งอนุมานจาก `OPENCLAW_LIVE_PROVIDERS` / `OPENCLAW_LIVE_GATEWAY_PROVIDERS` - - override ด้วยตนเองด้วย `OPENCLAW_DOCKER_AUTH_DIRS=all`, `OPENCLAW_DOCKER_AUTH_DIRS=none` หรือรายการคั่นด้วยจุลภาค เช่น `OPENCLAW_DOCKER_AUTH_DIRS=.claude,.codex` -- `OPENCLAW_LIVE_GATEWAY_MODELS=...` / `OPENCLAW_LIVE_MODELS=...` เพื่อจำกัดการรัน +- ไดเรกทอรี/ไฟล์ auth ของ CLI ภายนอกภายใต้ `$HOME` จะถูก mount แบบอ่านอย่างเดียวภายใต้ `/host-auth...` แล้วคัดลอกไปยัง `/home/node/...` ก่อนเริ่มเทสต์ + - ไดเรกทอรีค่าเริ่มต้น: `.minimax` + - ไฟล์ค่าเริ่มต้น: `~/.codex/auth.json`, `~/.codex/config.toml`, `.claude.json`, `~/.claude/.credentials.json`, `~/.claude/settings.json`, `~/.claude/settings.local.json` + - การรัน provider ที่จำกัดขอบเขตจะ mount เฉพาะไดเรกทอรี/ไฟล์ที่จำเป็นซึ่งอนุมานจาก `OPENCLAW_LIVE_PROVIDERS` / `OPENCLAW_LIVE_GATEWAY_PROVIDERS` + - override ด้วยตนเองด้วย `OPENCLAW_DOCKER_AUTH_DIRS=all`, `OPENCLAW_DOCKER_AUTH_DIRS=none` หรือรายการคั่นด้วยคอมมา เช่น `OPENCLAW_DOCKER_AUTH_DIRS=.claude,.codex` +- `OPENCLAW_LIVE_GATEWAY_MODELS=...` / `OPENCLAW_LIVE_MODELS=...` เพื่อจำกัดขอบเขตการรัน - `OPENCLAW_LIVE_GATEWAY_PROVIDERS=...` / `OPENCLAW_LIVE_PROVIDERS=...` เพื่อกรอง provider ภายในคอนเทนเนอร์ -- `OPENCLAW_SKIP_DOCKER_BUILD=1` เพื่อนำ image `openclaw:local-live` ที่มีอยู่กลับมาใช้สำหรับการรันซ้ำที่ไม่ต้อง rebuild +- `OPENCLAW_SKIP_DOCKER_BUILD=1` เพื่อใช้อิมเมจ `openclaw:local-live` ที่มีอยู่แล้วซ้ำสำหรับการรันซ้ำที่ไม่ต้องบิลด์ใหม่ - `OPENCLAW_LIVE_REQUIRE_PROFILE_KEYS=1` เพื่อให้แน่ใจว่า creds มาจาก profile store (ไม่ใช่ env) -- `OPENCLAW_OPENWEBUI_MODEL=...` เพื่อเลือกโมเดลที่ gateway expose สำหรับ smoke Open WebUI -- `OPENCLAW_OPENWEBUI_PROMPT=...` เพื่อ override prompt ตรวจ nonce ที่ใช้โดย smoke Open WebUI -- `OPENWEBUI_IMAGE=...` เพื่อ override tag image Open WebUI ที่ pin ไว้ +- `OPENCLAW_OPENWEBUI_MODEL=...` เพื่อเลือกโมเดลที่ Gateway เปิดเผยสำหรับ smoke ของ Open WebUI +- `OPENCLAW_OPENWEBUI_PROMPT=...` เพื่อ override prompt ตรวจสอบ nonce ที่ใช้โดย smoke ของ Open WebUI +- `OPENWEBUI_IMAGE=...` เพื่อ override tag อิมเมจ Open WebUI ที่ pin ไว้ -## ตรวจสอบความสมเหตุสมผลของเอกสาร +## การตรวจสุขภาพเอกสาร -รันการตรวจเอกสารหลังแก้ไขเอกสาร: `pnpm check:docs` +รันการตรวจสอบเอกสารหลังแก้ไขเอกสาร: `pnpm check:docs` รันการตรวจสอบ anchor ของ Mintlify แบบเต็มเมื่อคุณต้องการตรวจ heading ภายในหน้าด้วย: `pnpm docs:check-links:anchors` ## Regression แบบออฟไลน์ (ปลอดภัยสำหรับ CI) -รายการเหล่านี้คือ regression แบบ “pipeline จริง” โดยไม่มี provider จริง: +รายการเหล่านี้เป็น regression ของ “pipeline จริง” โดยไม่มี provider จริง: -- การเรียก tool ของ Gateway (mock OpenAI, gateway จริง + ลูป agent): `src/gateway/gateway.test.ts` (case: "runs a mock OpenAI tool call end-to-end via gateway agent loop") -- wizard ของ Gateway (WS `wizard.start`/`wizard.next`, เขียน config + บังคับใช้ auth): `src/gateway/gateway.test.ts` (case: "runs wizard over ws and writes auth token config") +- การเรียกใช้เครื่องมือของ Gateway (mock OpenAI, Gateway จริง + agent loop จริง): `src/gateway/gateway.test.ts` (case: "runs a mock OpenAI tool call end-to-end via gateway agent loop") +- วิซาร์ด Gateway (WS `wizard.start`/`wizard.next`, เขียน config + บังคับใช้ auth): `src/gateway/gateway.test.ts` (case: "runs wizard over ws and writes auth token config") -## Eval ความน่าเชื่อถือของ agent (skills) +## Eval ความน่าเชื่อถือของ agent (Skills) -เรามีการทดสอบที่ปลอดภัยสำหรับ CI อยู่แล้วบางส่วน ซึ่งทำงานคล้าย “eval ความน่าเชื่อถือของ agent”: +เรามีเทสต์ที่ปลอดภัยสำหรับ CI อยู่แล้วบางส่วนซึ่งทำงานเหมือน “eval ความน่าเชื่อถือของ agent”: -- การเรียก tool แบบ mock ผ่าน gateway จริง + ลูป agent (`src/gateway/gateway.test.ts`) -- flow wizard แบบ end-to-end ที่ตรวจสอบ wiring ของ session และผลกระทบต่อ config (`src/gateway/gateway.test.ts`) +- การเรียกใช้เครื่องมือแบบ mock ผ่าน Gateway จริง + agent loop จริง (`src/gateway/gateway.test.ts`) +- โฟลว์วิซาร์ดแบบ end-to-end ที่ตรวจสอบ wiring ของ session และผลของ config (`src/gateway/gateway.test.ts`) -สิ่งที่ยังขาดสำหรับ skills (ดู [Skills](/th/tools/skills)): +สิ่งที่ยังขาดสำหรับ Skills (ดู [Skills](/th/tools/skills)): -- **การตัดสินใจ:** เมื่อมีการระบุ skills ใน prompt agent เลือก skill ที่ถูกต้องหรือไม่ (หรือหลีกเลี่ยงตัวที่ไม่เกี่ยวข้องหรือไม่)? -- **การปฏิบัติตามข้อกำหนด:** agent อ่าน `SKILL.md` ก่อนใช้งานและทำตามขั้นตอน/args ที่กำหนดหรือไม่? -- **สัญญา workflow:** สถานการณ์หลาย turn ที่ assert ลำดับ tool, การส่งต่อประวัติ session และขอบเขต sandbox +- **การตัดสินใจ:** เมื่อ Skills ถูกระบุไว้ใน prompt agent เลือก skill ที่ถูกต้องหรือไม่ (หรือหลีกเลี่ยง skill ที่ไม่เกี่ยวข้องหรือไม่)? +- **การปฏิบัติตามข้อกำหนด:** agent อ่าน `SKILL.md` ก่อนใช้และทำตามขั้นตอน/args ที่กำหนดหรือไม่? +- **สัญญาเวิร์กโฟลว์:** สถานการณ์หลาย turn ที่ assert ลำดับเครื่องมือ, การส่งต่อประวัติ session และขอบเขต sandbox -Eval ในอนาคตควรเน้น deterministic ก่อน: +eval ในอนาคตควรเริ่มจากการกำหนดผลลัพธ์ได้แน่นอนก่อน: -- ตัวรันสถานการณ์ที่ใช้ provider แบบ mock เพื่อ assert การเรียก tool + ลำดับ, การอ่านไฟล์ skill และ wiring ของ session -- ชุดสถานการณ์ขนาดเล็กที่โฟกัส skill (ใช้เทียบกับหลีกเลี่ยง, gating, prompt injection) -- Eval สดแบบเลือกใช้ได้ (opt-in, ควบคุมด้วย env) หลังจากมีชุดที่ปลอดภัยสำหรับ CI แล้วเท่านั้น +- scenario runner ที่ใช้ provider แบบ mock เพื่อ assert การเรียกใช้เครื่องมือ + ลำดับ, การอ่านไฟล์ skill และ wiring ของ session +- ชุดสถานการณ์ขนาดเล็กที่เน้น skill (ใช้เทียบกับหลีกเลี่ยง, gating, prompt injection) +- eval แบบ live ที่เป็นตัวเลือก (opt-in, ควบคุมด้วย env) เฉพาะหลังจากมีชุดที่ปลอดภัยสำหรับ CI แล้ว -## การทดสอบสัญญา (รูปทรงของ plugin และ channel) +## เทสต์สัญญา (รูปทรงของ Plugin และช่องทาง) -การทดสอบสัญญาตรวจสอบว่า plugin และ channel ที่ลงทะเบียนทุกตัวสอดคล้องกับ -สัญญา interface ของตัวเอง โดยจะวนผ่าน plugin ทั้งหมดที่ค้นพบและรันชุด -assertion ด้านรูปทรงและพฤติกรรม lane unit เริ่มต้นของ `pnpm test` ตั้งใจ -ข้ามไฟล์ seam ร่วมและ smoke เหล่านี้ ให้รันคำสั่งสัญญาอย่างชัดเจน -เมื่อคุณแตะ surface ร่วมของ channel หรือ provider +เทสต์สัญญาตรวจสอบว่า Plugin และช่องทางที่ลงทะเบียนทุกรายการสอดคล้องกับ +สัญญาอินเทอร์เฟซของตน เทสต์จะวนผ่าน Plugin ทั้งหมดที่ค้นพบและรันชุด +assertion ด้านรูปทรงและพฤติกรรม เลน unit ของ `pnpm test` ค่าเริ่มต้นตั้งใจ +ข้ามไฟล์ shared seam และ smoke เหล่านี้; ให้รันคำสั่งสัญญาอย่างชัดเจน +เมื่อคุณแตะพื้นผิวช่องทางหรือ provider ที่ใช้ร่วมกัน ### คำสั่ง - สัญญาทั้งหมด: `pnpm test:contracts` -- เฉพาะสัญญา channel: `pnpm test:contracts:channels` -- เฉพาะสัญญา provider: `pnpm test:contracts:plugins` +- สัญญาช่องทางเท่านั้น: `pnpm test:contracts:channels` +- สัญญา provider เท่านั้น: `pnpm test:contracts:plugins` -### สัญญา channel +### สัญญาช่องทาง อยู่ใน `src/channels/plugins/contracts/*.contract.test.ts`: - **plugin** - รูปทรง Plugin พื้นฐาน (id, name, capabilities) -- **setup** - สัญญา setup wizard -- **session-binding** - พฤติกรรมการ bind session +- **setup** - สัญญาวิซาร์ดการตั้งค่า +- **session-binding** - พฤติกรรมการผูก session - **outbound-payload** - โครงสร้าง payload ของข้อความ - **inbound** - การจัดการข้อความขาเข้า -- **actions** - handler action ของ channel +- **actions** - handler action ของช่องทาง - **threading** - การจัดการ thread ID - **directory** - API directory/roster - **group-policy** - การบังคับใช้นโยบายกลุ่ม @@ -781,45 +742,45 @@ assertion ด้านรูปทรงและพฤติกรรม lane u อยู่ใน `src/plugins/contracts/*.contract.test.ts` -- **status** - probe สถานะ channel +- **status** - โพรบสถานะช่องทาง - **registry** - รูปทรง registry ของ Plugin ### สัญญา provider อยู่ใน `src/plugins/contracts/*.contract.test.ts`: -- **auth** - สัญญา auth flow -- **auth-choice** - การเลือก/ตัวเลือก auth -- **catalog** - API catalog ของโมเดล +- **auth** - สัญญาโฟลว์ auth +- **auth-choice** - ตัวเลือก/การเลือก auth +- **catalog** - API แค็ตตาล็อกโมเดล - **discovery** - การค้นพบ Plugin - **loader** - การโหลด Plugin - **runtime** - runtime ของ provider -- **shape** - รูปทรง/interface ของ Plugin -- **wizard** - setup wizard +- **shape** - รูปทรง/อินเทอร์เฟซของ Plugin +- **wizard** - วิซาร์ดการตั้งค่า ### ควรรันเมื่อใด - หลังจากเปลี่ยน export หรือ subpath ของ plugin-sdk -- หลังจากเพิ่มหรือแก้ไข channel หรือ provider Plugin +- หลังจากเพิ่มหรือแก้ไขช่องทางหรือ Plugin provider - หลังจาก refactor การลงทะเบียนหรือการค้นพบ Plugin -การทดสอบสัญญารันใน CI และไม่ต้องใช้ key API จริง +เทสต์สัญญารันใน CI และไม่ต้องใช้คีย์ API จริง -## การเพิ่ม regression (แนวทาง) +## การเพิ่ม regression (คำแนะนำ) -เมื่อคุณแก้ไขปัญหา provider/model ที่พบจากการรันสด: +เมื่อคุณแก้ปัญหา provider/model ที่พบจาก live: -- เพิ่ม regression ที่ปลอดภัยสำหรับ CI หากเป็นไปได้ (provider แบบ mock/stub หรือจับ transformation ของรูปทรงคำขอที่ตรงตัว) -- หากเป็นเรื่องเฉพาะการรันสดโดยเนื้อแท้ (rate limit, นโยบาย auth) ให้คงการทดสอบสดให้แคบและ opt-in ผ่านตัวแปร env -- ควร target layer ที่เล็กที่สุดซึ่งจับ bug ได้: - - bug การแปลง/replay คำขอของ provider → การทดสอบ models โดยตรง - - bug pipeline ของ session/history/tool ใน gateway → smoke สดของ gateway หรือการทดสอบ mock gateway ที่ปลอดภัยสำหรับ CI -- guardrail การ traverse SecretRef: - - `src/secrets/exec-secret-ref-id-parity.test.ts` derive target ตัวอย่างหนึ่งรายการต่อคลาส SecretRef จาก metadata ของ registry (`listSecretTargetRegistryEntries()`) แล้ว assert ว่า exec id แบบ traversal-segment ถูกปฏิเสธ - - หากคุณเพิ่ม target family ของ SecretRef ใหม่ที่มี `includeInPlan` ใน `src/secrets/target-registry-data.ts` ให้อัปเดต `classifyTargetClass` ในการทดสอบนั้น การทดสอบตั้งใจ fail เมื่อมี target id ที่จัดคลาสไม่ได้ เพื่อไม่ให้คลาสใหม่ถูกข้ามอย่างเงียบ ๆ +- เพิ่ม regression ที่ปลอดภัยสำหรับ CI ถ้าเป็นไปได้ (mock/stub provider หรือบันทึกการแปลงรูปทรงคำขอที่ตรงจุด) +- ถ้าเป็นเรื่อง live-only โดยธรรมชาติ (rate limit, นโยบาย auth) ให้เทสต์ live มีขอบเขตแคบและ opt-in ผ่านตัวแปร env +- ควรเล็งไปที่ชั้นที่เล็กที่สุดซึ่งจับบั๊กได้: + - บั๊กการแปลง/เล่นซ้ำคำขอของ provider → เทสต์ models โดยตรง + - บั๊ก pipeline ของ session/history/tool ใน Gateway → smoke live ของ Gateway หรือเทสต์ mock ของ Gateway ที่ปลอดภัยสำหรับ CI +- guardrail การ traversal ของ SecretRef: + - `src/secrets/exec-secret-ref-id-parity.test.ts` derive target ตัวอย่างหนึ่งรายการต่อคลาส SecretRef จากเมตาดาต้า registry (`listSecretTargetRegistryEntries()`), จากนั้น assert ว่า exec id ที่มี traversal segment ถูกปฏิเสธ + - หากคุณเพิ่มตระกูล target ของ SecretRef ใหม่ที่มี `includeInPlan` ใน `src/secrets/target-registry-data.ts` ให้อัปเดต `classifyTargetClass` ในเทสต์นั้น เทสต์ตั้งใจให้ล้มเหลวเมื่อพบ target id ที่ยังไม่ได้จัดคลาส เพื่อไม่ให้คลาสใหม่ถูกข้ามอย่างเงียบ ๆ ## ที่เกี่ยวข้อง -- [การทดสอบแบบสด](/th/help/testing-live) -- [การทดสอบอัปเดตและ plugins](/th/help/testing-updates-plugins) +- [การทดสอบ live](/th/help/testing-live) +- [การทดสอบอัปเดตและ Plugin](/th/help/testing-updates-plugins) - [CI](/th/ci) diff --git a/docs/th/install/updating.md b/docs/th/install/updating.md index c799ca8d3..f001d5f1f 100644 --- a/docs/th/install/updating.md +++ b/docs/th/install/updating.md @@ -1,29 +1,29 @@ --- read_when: - การอัปเดต OpenClaw - - มีบางอย่างใช้งานไม่ได้หลังจากอัปเดต -summary: การอัปเดต OpenClaw อย่างปลอดภัย (ติดตั้งแบบโกลบอลหรือจากซอร์ส) พร้อมกลยุทธ์การย้อนกลับ + - มีบางอย่างขัดข้องหลังจากการอัปเดต +summary: การอัปเดต OpenClaw อย่างปลอดภัย (การติดตั้งทั่วทั้งระบบหรือจากซอร์สโค้ด) พร้อมกลยุทธ์การย้อนกลับ title: การอัปเดต x-i18n: - generated_at: "2026-05-03T21:34:50Z" + generated_at: "2026-05-04T07:05:15Z" model: gpt-5.5 provider: openai - source_hash: f9e26ea71748dfd1573cdca01126bf29ebc56be56eac604e2b6a009b463820d1 + source_hash: 3c9ff1d70d74f45efea3c148718e5cbc74001ce3d924b760edc4d68622d23714 source_path: install/updating.md workflow: 16 --- -อัปเดต OpenClaw ให้เป็นปัจจุบันอยู่เสมอ +ทำให้ OpenClaw เป็นปัจจุบันอยู่เสมอ ## แนะนำ: `openclaw update` -วิธีอัปเดตที่เร็วที่สุด คำสั่งนี้ตรวจหาประเภทการติดตั้งของคุณ (npm หรือ git), ดึงเวอร์ชันล่าสุด, รัน `openclaw doctor`, และรีสตาร์ต Gateway +วิธีอัปเดตที่เร็วที่สุด โดยจะตรวจจับประเภทการติดตั้งของคุณ (npm หรือ git), ดึงเวอร์ชันล่าสุด, รัน `openclaw doctor`, และรีสตาร์ต Gateway ```bash openclaw update ``` -หากต้องการสลับช่องทางหรือตั้งเป้าเป็นเวอร์ชันเฉพาะ: +หากต้องการสลับช่องทางหรือระบุเวอร์ชันเป้าหมาย: ```bash openclaw update --channel beta @@ -32,22 +32,22 @@ openclaw update --tag main openclaw update --dry-run # preview without applying ``` -`openclaw update` ไม่รับ `--verbose` สำหรับการวินิจฉัยการอัปเดต ให้ใช้ +`openclaw update` ไม่รองรับ `--verbose` สำหรับการวินิจฉัยการอัปเดต ให้ใช้ `--dry-run` เพื่อดูตัวอย่างการดำเนินการที่วางแผนไว้, `--json` สำหรับผลลัพธ์แบบมีโครงสร้าง, หรือ -`openclaw update status --json` เพื่อตรวจสอบสถานะช่องทางและความพร้อมใช้งาน -ตัวติดตั้งมีแฟล็ก `--verbose` ของตัวเอง แต่แฟล็กนั้นไม่ได้เป็นส่วนหนึ่งของ +`openclaw update status --json` เพื่อตรวจสอบสถานะช่องทางและความพร้อมใช้งาน ตัวติดตั้ง +มีแฟล็ก `--verbose` ของตัวเอง แต่แฟล็กนั้นไม่ได้เป็นส่วนหนึ่งของ `openclaw update` -`--channel beta` จะเลือก beta ก่อน แต่ runtime จะ fallback ไปที่ stable/latest เมื่อ -แท็ก beta ไม่มีอยู่หรือเก่ากว่ารีลีส stable ล่าสุด ใช้ `--tag beta` -หากคุณต้องการ npm beta dist-tag ดิบสำหรับการอัปเดตแพ็กเกจแบบครั้งเดียว +`--channel beta` จะเลือก beta เป็นหลัก แต่รันไทม์จะย้อนกลับไปใช้ stable/latest เมื่อ +แท็ก beta หายไปหรือเก่ากว่ารุ่น stable ล่าสุด ใช้ `--tag beta` +หากคุณต้องการ dist-tag beta ดิบของ npm สำหรับการอัปเดตแพ็กเกจแบบครั้งเดียว ดู [ช่องทางการพัฒนา](/th/install/development-channels) สำหรับความหมายของช่องทาง -## สลับระหว่างการติดตั้ง npm และ git +## สลับระหว่างการติดตั้งแบบ npm และ git ใช้ช่องทางเมื่อคุณต้องการเปลี่ยนประเภทการติดตั้ง ตัวอัปเดตจะเก็บ -สถานะ, config, credentials, และ workspace ของคุณไว้ใน `~/.openclaw`; มันจะเปลี่ยนเฉพาะ +สถานะ, คอนฟิก, ข้อมูลประจำตัว, และเวิร์กสเปซของคุณไว้ใน `~/.openclaw`; โดยจะเปลี่ยนเฉพาะ การติดตั้งโค้ด OpenClaw ที่ CLI และ Gateway ใช้เท่านั้น ```bash @@ -65,10 +65,10 @@ openclaw update --channel dev --dry-run openclaw update --channel stable --dry-run ``` -ช่องทาง `dev` ทำให้มั่นใจว่ามี git checkout, build มัน, และติดตั้ง CLI แบบ global -จาก checkout นั้น ช่องทาง `stable` และ `beta` ใช้การติดตั้งแพ็กเกจ หาก -Gateway ติดตั้งอยู่แล้ว `openclaw update` จะรีเฟรช service metadata -และรีสตาร์ต เว้นแต่คุณจะส่ง `--no-restart` +ช่องทาง `dev` จะทำให้แน่ใจว่ามี git checkout, สร้างมัน, และติดตั้ง CLI แบบ global +จาก checkout นั้น ช่องทาง `stable` และ `beta` ใช้การติดตั้งแบบแพ็กเกจ หาก +Gateway ติดตั้งอยู่แล้ว `openclaw update` จะรีเฟรชข้อมูลเมตาของบริการ +และรีสตาร์ตบริการนั้น เว้นแต่คุณจะส่ง `--no-restart` ## ทางเลือก: รันตัวติดตั้งอีกครั้ง @@ -76,37 +76,42 @@ Gateway ติดตั้งอยู่แล้ว `openclaw update` จะ curl -fsSL https://openclaw.ai/install.sh | bash ``` -เพิ่ม `--no-onboard` เพื่อข้าม onboarding หากต้องการบังคับประเภทการติดตั้งเฉพาะผ่าน +เพิ่ม `--no-onboard` เพื่อข้ามการเริ่มต้นใช้งาน หากต้องการบังคับประเภทการติดตั้งเฉพาะผ่าน ตัวติดตั้ง ให้ส่ง `--install-method git --no-onboard` หรือ `--install-method npm --no-onboard` หาก `openclaw update` ล้มเหลวหลังจากขั้นตอนติดตั้งแพ็กเกจ npm ให้รัน -ตัวติดตั้งอีกครั้ง ตัวติดตั้งจะไม่เรียกตัวอัปเดตเก่า; มันรันการติดตั้งแพ็กเกจ -global โดยตรงและสามารถกู้คืนการติดตั้ง npm ที่อัปเดตไปบางส่วนได้ +ตัวติดตั้งอีกครั้ง ตัวติดตั้งจะไม่เรียกตัวอัปเดตเก่า แต่จะรันการติดตั้งแพ็กเกจ +global โดยตรง และสามารถกู้คืนการติดตั้ง npm ที่อัปเดตไปบางส่วนได้ ```bash curl -fsSL https://openclaw.ai/install.sh | bash -s -- --install-method npm ``` -หากต้องการตรึงการกู้คืนไว้ที่เวอร์ชันหรือ dist-tag เฉพาะ ให้เพิ่ม `--version`: +หากต้องการตรึงการกู้คืนไว้กับเวอร์ชันหรือ dist-tag เฉพาะ ให้เพิ่ม `--version`: ```bash curl -fsSL https://openclaw.ai/install.sh | bash -s -- --install-method npm --version ``` -## ทางเลือก: npm, pnpm, หรือ bun แบบแมนนวล +## ทางเลือก: npm, pnpm, หรือ bun แบบ manual ```bash npm i -g openclaw@latest ``` -เมื่อ `openclaw update` จัดการการติดตั้ง npm แบบ global มันจะติดตั้งเป้าหมายลงใน -temporary npm prefix ก่อน, ตรวจสอบ packaged `dist` inventory, แล้วจึงสลับ -package tree ที่สะอาดเข้าไปใน global prefix จริง วิธีนี้หลีกเลี่ยงไม่ให้ npm ซ้อนทับ -แพ็กเกจใหม่ลงบนไฟล์เก่าที่ค้างจากแพ็กเกจเดิม หากคำสั่งติดตั้งล้มเหลว -OpenClaw จะลองอีกครั้งหนึ่งพร้อม `--omit=optional` การลองซ้ำนี้ช่วยโฮสต์ที่ native -optional dependencies คอมไพล์ไม่ได้ ขณะเดียวกันก็ยังทำให้เห็น failure เดิม -หาก fallback ล้มเหลวเช่นกัน +ควรใช้ `openclaw update` สำหรับการติดตั้งที่มีการควบคุมดูแล เพราะสามารถประสาน +การสลับแพ็กเกจกับบริการ Gateway ที่กำลังทำงานอยู่ได้ หากคุณอัปเดตแบบ manual ขณะที่ +Gateway ที่จัดการอยู่กำลังทำงาน ให้รีสตาร์ต Gateway ทันทีหลังจากตัวจัดการแพ็กเกจ +ทำงานเสร็จ เพื่อไม่ให้โปรเซสเก่ายังคงให้บริการจากไฟล์แพ็กเกจที่ถูกแทนที่แล้ว + +เมื่อ `openclaw update` จัดการการติดตั้ง npm แบบ global จะติดตั้งเป้าหมายลงใน +prefix npm ชั่วคราวก่อน, ตรวจสอบรายการ `dist` ที่แพ็กไว้, แล้วจึงสลับ +แผนผังแพ็กเกจที่สะอาดเข้าไปใน prefix global จริง วิธีนี้หลีกเลี่ยงไม่ให้ npm ทับซ้อน +แพ็กเกจใหม่ลงบนไฟล์ค้างเก่าจากแพ็กเกจเดิม หากคำสั่งติดตั้งล้มเหลว +OpenClaw จะลองอีกครั้งหนึ่งด้วย `--omit=optional` การลองใหม่นี้ช่วยโฮสต์ที่ dependency +แบบ optional ที่เป็น native ไม่สามารถคอมไพล์ได้ ขณะที่ยังคงแสดงความล้มเหลวเดิม +หาก fallback ก็ล้มเหลวเช่นกัน ```bash pnpm add -g openclaw@latest @@ -116,31 +121,31 @@ pnpm add -g openclaw@latest bun add -g openclaw@latest ``` -### หัวข้อการติดตั้ง npm ขั้นสูง +### หัวข้อขั้นสูงสำหรับการติดตั้ง npm - - OpenClaw ถือว่าการติดตั้ง global แบบแพ็กเกจเป็นแบบอ่านอย่างเดียวใน runtime แม้ว่า directory แพ็กเกจ global จะเขียนได้โดยผู้ใช้ปัจจุบันก็ตาม การติดตั้งแพ็กเกจ Plugin จะอยู่ใน npm/git roots ที่ OpenClaw เป็นเจ้าของภายใต้ directory config ของผู้ใช้ และการเริ่มต้น Gateway จะไม่แก้ไข package tree ของ OpenClaw + + OpenClaw ถือว่าการติดตั้ง global แบบแพ็กเกจเป็นแบบอ่านอย่างเดียวขณะรันไทม์ แม้ว่าไดเรกทอรีแพ็กเกจ global จะเขียนได้โดยผู้ใช้ปัจจุบันก็ตาม การติดตั้งแพ็กเกจ Plugin จะอยู่ในราก npm/git ที่ OpenClaw เป็นเจ้าของภายใต้ไดเรกทอรีคอนฟิกของผู้ใช้ และการเริ่มต้น Gateway จะไม่แก้ไขแผนผังแพ็กเกจ OpenClaw - การตั้งค่า npm บน Linux บางแบบติดตั้งแพ็กเกจ global ไว้ใน directory ที่ root เป็นเจ้าของ เช่น `/usr/lib/node_modules/openclaw` OpenClaw รองรับ layout นี้เพราะคำสั่งติดตั้ง/อัปเดต Plugin จะเขียนนอก directory แพ็กเกจ global นั้น + การตั้งค่า npm บน Linux บางแบบติดตั้งแพ็กเกจ global ไว้ใต้ไดเรกทอรีที่ root เป็นเจ้าของ เช่น `/usr/lib/node_modules/openclaw` OpenClaw รองรับรูปแบบนี้ เพราะคำสั่งติดตั้ง/อัปเดต Plugin จะเขียนนอกไดเรกทอรีแพ็กเกจ global นั้น - - ให้ OpenClaw มีสิทธิ์เขียนไปยัง config/state roots ของมัน เพื่อให้การติดตั้ง Plugin แบบ explicit, การอัปเดต Plugin, และการล้างข้อมูลของ doctor สามารถบันทึกการเปลี่ยนแปลงได้: + + ให้สิทธิ์ OpenClaw เขียนไปยังรากคอนฟิก/สถานะ เพื่อให้การติดตั้ง Plugin แบบ explicit, การอัปเดต Plugin, และการล้างข้อมูลโดย doctor สามารถบันทึกการเปลี่ยนแปลงได้: ```ini ReadWritePaths=/var/lib/openclaw /home/openclaw/.openclaw /tmp ``` - - ก่อนการอัปเดตแพ็กเกจและการติดตั้ง Plugin แบบ explicit, OpenClaw จะพยายามตรวจสอบพื้นที่ดิสก์แบบ best-effort สำหรับ volume เป้าหมาย พื้นที่เหลือน้อยจะสร้างคำเตือนพร้อม path ที่ตรวจสอบ แต่จะไม่บล็อกการอัปเดต เพราะ filesystem quotas, snapshots, และ network volumes อาจเปลี่ยนหลังจากการตรวจสอบได้ การติดตั้งของ package-manager จริงและการตรวจสอบหลังติดตั้งยังคงเป็นแหล่งอ้างอิงหลัก + + ก่อนการอัปเดตแพ็กเกจและการติดตั้ง Plugin แบบ explicit OpenClaw จะพยายามตรวจสอบพื้นที่ดิสก์แบบ best-effort สำหรับโวลุ่มเป้าหมาย พื้นที่เหลือน้อยจะสร้างคำเตือนพร้อม path ที่ตรวจสอบ แต่จะไม่บล็อกการอัปเดต เพราะ quota ของไฟล์ซิสเต็ม, snapshot, และโวลุ่มเครือข่ายอาจเปลี่ยนหลังการตรวจสอบได้ การติดตั้งจริงด้วยตัวจัดการแพ็กเกจและการตรวจสอบหลังติดตั้งยังคงเป็นหลักฐานชี้ขาด ## ตัวอัปเดตอัตโนมัติ -ตัวอัปเดตอัตโนมัติปิดอยู่ตามค่าเริ่มต้น เปิดใช้งานใน `~/.openclaw/openclaw.json`: +ตัวอัปเดตอัตโนมัติปิดอยู่เป็นค่าเริ่มต้น เปิดใช้งานใน `~/.openclaw/openclaw.json`: ```json5 { @@ -156,21 +161,21 @@ bun add -g openclaw@latest } ``` -| ช่องทาง | พฤติกรรม | +| ช่องทาง | พฤติกรรม | | -------- | ------------------------------------------------------------------------------------------------------------- | -| `stable` | รอ `stableDelayHours` แล้วจึง apply พร้อม deterministic jitter ทั่ว `stableJitterHours` (กระจาย rollout) | -| `beta` | ตรวจสอบทุก `betaCheckIntervalHours` (ค่าเริ่มต้น: ทุกชั่วโมง) และ apply ทันที | -| `dev` | ไม่มีการ apply อัตโนมัติ ใช้ `openclaw update` แบบแมนนวล | +| `stable` | รอ `stableDelayHours` แล้วจึงใช้การอัปเดตพร้อม jitter แบบกำหนดแน่นอนทั่ว `stableJitterHours` (การทยอยปล่อยแบบกระจาย) | +| `beta` | ตรวจสอบทุก `betaCheckIntervalHours` (ค่าเริ่มต้น: ทุกชั่วโมง) และใช้การอัปเดตทันที | +| `dev` | ไม่มีการใช้การอัปเดตโดยอัตโนมัติ ใช้ `openclaw update` แบบ manual | -Gateway ยัง log คำแนะนำการอัปเดตเมื่อเริ่มต้นด้วย (ปิดได้ด้วย `update.checkOnStart: false`) -สำหรับการ downgrade หรือการกู้คืนจากเหตุการณ์ ให้ตั้ง `OPENCLAW_NO_AUTO_UPDATE=1` ใน environment ของ Gateway เพื่อบล็อกการ apply อัตโนมัติ แม้เมื่อกำหนดค่า `update.auto.enabled` ไว้ คำแนะนำการอัปเดตตอนเริ่มต้นยังคงรันได้ เว้นแต่ `update.checkOnStart` จะถูกปิดด้วย +Gateway ยังบันทึกคำใบ้การอัปเดตเมื่อเริ่มทำงานด้วย (ปิดได้ด้วย `update.checkOnStart: false`) +สำหรับการดาวน์เกรดหรือการกู้คืนจากเหตุการณ์ ให้ตั้ง `OPENCLAW_NO_AUTO_UPDATE=1` ในสภาพแวดล้อมของ Gateway เพื่อบล็อกการใช้การอัปเดตอัตโนมัติ แม้จะกำหนดค่า `update.auto.enabled` ไว้แล้วก็ตาม คำใบ้การอัปเดตตอนเริ่มทำงานยังคงรันได้ เว้นแต่ `update.checkOnStart` จะถูกปิดด้วย -การอัปเดต package-manager ที่ร้องขอผ่าน handler ของ live Gateway control-plane -จะบังคับให้รีสตาร์ตการอัปเดตแบบไม่เลื่อนเวลาและไม่มี cooldown หลังจากสลับแพ็กเกจ -วิธีนี้หลีกเลี่ยงการปล่อย process ในหน่วยความจำเก่าให้อยู่ต่อไปนานพอที่จะ lazy-load chunks -จาก package tree ที่ถูกแทนที่ไปแล้ว Shell `openclaw update` -ยังคงเป็นเส้นทางที่แนะนำสำหรับการติดตั้งที่มีการกำกับดูแล เพราะมันสามารถหยุดและ -รีสตาร์ต service รอบการอัปเดตได้ +การอัปเดตตัวจัดการแพ็กเกจที่ร้องขอผ่าน handler ของ control-plane ของ Gateway สด +จะบังคับให้รีสตาร์ตการอัปเดตแบบไม่เลื่อนเวลาและไม่มี cooldown หลังจากการสลับแพ็กเกจ +วิธีนี้หลีกเลี่ยงการทิ้งโปรเซสเก่าในหน่วยความจำไว้นานพอที่จะ lazy-load ชังก์ +จากแผนผังแพ็กเกจที่ถูกแทนที่ไปแล้ว คำสั่งเชลล์ `openclaw update` +ยังคงเป็นเส้นทางที่แนะนำสำหรับการติดตั้งที่มีการควบคุมดูแล เพราะสามารถหยุดและ +รีสตาร์ตบริการรอบการอัปเดตได้ ## หลังจากอัปเดต @@ -182,7 +187,7 @@ Gateway ยัง log คำแนะนำการอัปเดตเมื openclaw doctor ``` -ย้าย config, audit นโยบาย DM, และตรวจสอบสุขภาพ Gateway รายละเอียด: [Doctor](/th/gateway/doctor) +ย้ายคอนฟิก, ตรวจสอบนโยบาย DM, และตรวจสอบสุขภาพ Gateway รายละเอียด: [Doctor](/th/gateway/doctor) ### รีสตาร์ต Gateway @@ -198,7 +203,7 @@ openclaw health -## Rollback +## ย้อนกลับ ### ตรึงเวอร์ชัน (npm) @@ -221,17 +226,17 @@ pnpm install && pnpm build openclaw gateway restart ``` -หากต้องการกลับไปเป็นล่าสุด: `git checkout main && git pull` +หากต้องการกลับไปยังล่าสุด: `git checkout main && git pull` ## หากคุณติดขัด -- รัน `openclaw doctor` อีกครั้งและอ่านผลลัพธ์อย่างละเอียด -- สำหรับ `openclaw update --channel dev` บน source checkouts, ตัวอัปเดตจะ auto-bootstrap `pnpm` เมื่อจำเป็น หากคุณเห็น pnpm/corepack bootstrap error ให้ติดตั้ง `pnpm` แบบแมนนวล (หรือเปิดใช้งาน `corepack` อีกครั้ง) แล้วรันการอัปเดตซ้ำ +- รัน `openclaw doctor` อีกครั้งและอ่านข้อความ output อย่างละเอียด +- สำหรับ `openclaw update --channel dev` บน source checkout ตัวอัปเดตจะ bootstrap `pnpm` โดยอัตโนมัติเมื่อจำเป็น หากคุณเห็นข้อผิดพลาด bootstrap ของ pnpm/corepack ให้ติดตั้ง `pnpm` แบบ manual (หรือเปิด `corepack` อีกครั้ง) แล้วรันการอัปเดตใหม่ - ตรวจสอบ: [การแก้ไขปัญหา](/th/gateway/troubleshooting) - ถามใน Discord: [https://discord.gg/clawd](https://discord.gg/clawd) ## ที่เกี่ยวข้อง - [ภาพรวมการติดตั้ง](/th/install): วิธีการติดตั้งทั้งหมด -- [Doctor](/th/gateway/doctor): การตรวจสอบสุขภาพหลังการอัปเดต -- [การย้ายข้อมูล](/th/install/migrating): คู่มือการย้ายข้อมูลเวอร์ชันหลัก +- [Doctor](/th/gateway/doctor): การตรวจสอบสุขภาพหลังอัปเดต +- [การย้าย](/th/install/migrating): คู่มือการย้ายเวอร์ชันหลัก diff --git a/docs/th/plugins/google-meet.md b/docs/th/plugins/google-meet.md index fa7b1c209..564732e8a 100644 --- a/docs/th/plugins/google-meet.md +++ b/docs/th/plugins/google-meet.md @@ -2,46 +2,44 @@ read_when: - คุณต้องการให้เอเจนต์ OpenClaw เข้าร่วมการประชุม Google Meet - คุณต้องการให้เอเจนต์ OpenClaw สร้างการประชุม Google Meet ใหม่ - - คุณกำลังกำหนดค่า Chrome, Chrome node หรือ Twilio เป็นการรับส่งของ Google Meet -summary: 'Plugin Google Meet: เข้าร่วม URL ของ Meet ที่ระบุชัดเจนผ่าน Chrome หรือ Twilio พร้อมค่าเริ่มต้นเสียงแบบเรียลไทม์' -title: Plugin สำหรับ Google Meet + - คุณกำลังกำหนดค่า Chrome, โหนด Chrome หรือ Twilio ให้เป็นทรานสปอร์ตของ Google Meet +summary: 'Plugin Google Meet: เข้าร่วม URL ของ Meet ที่ระบุอย่างชัดเจนผ่าน Chrome หรือ Twilio พร้อมค่าเริ่มต้นสำหรับการตอบกลับของเอเจนต์' +title: Plugin Google Meet x-i18n: - generated_at: "2026-05-04T02:25:36Z" + generated_at: "2026-05-04T07:05:53Z" model: gpt-5.5 provider: openai - source_hash: 77ab70d27d47bcc037144c7c6cfad6f93f307355b6ebcf3ee75c85b96a24af2f + source_hash: 4268ad895bbf83d649b9571c0888c27eb982ad9710dfb408f22f7818cdc5dbcb source_path: plugins/google-meet.md workflow: 16 --- -การรองรับผู้เข้าร่วม Google Meet สำหรับ OpenClaw — Plugin จงใจออกแบบให้ชัดเจน: +Google Meet รองรับผู้เข้าร่วมสำหรับ OpenClaw — Plugin ตั้งใจออกแบบให้ชัดเจน: -- เข้าร่วมเฉพาะ URL `https://meet.google.com/...` ที่ระบุอย่างชัดเจนเท่านั้น +- เข้าร่วมได้เฉพาะ URL `https://meet.google.com/...` ที่ระบุไว้อย่างชัดเจนเท่านั้น - สามารถสร้างพื้นที่ Meet ใหม่ผ่าน Google Meet API แล้วเข้าร่วม URL ที่ส่งกลับมา -- `realtime` voice เป็นโหมดเริ่มต้น -- Realtime voice สามารถเรียกกลับเข้าสู่ agent OpenClaw แบบเต็มได้เมื่อต้องใช้การให้เหตุผลที่ลึกขึ้นหรือเครื่องมือ -- Agents เลือกพฤติกรรมการเข้าร่วมด้วย `mode`: ใช้ `realtime` สำหรับการฟัง/พูดตอบกลับแบบสด หรือ `transcribe` เพื่อเข้าร่วม/ควบคุมเบราว์เซอร์โดยไม่มีสะพาน realtime voice -- การยืนยันตัวตนเริ่มต้นเป็น Google OAuth ส่วนบุคคลหรือโปรไฟล์ Chrome ที่ลงชื่อเข้าใช้อยู่แล้ว -- ไม่มีการประกาศความยินยอมอัตโนมัติ -- แบ็กเอนด์เสียง Chrome เริ่มต้นคือ `BlackHole 2ch` +- `agent` คือโหมดพูดตอบกลับเริ่มต้น: การถอดเสียงแบบเรียลไทม์จะฟัง, Agent ของ OpenClaw ที่กำหนดค่าไว้จะตอบ, และ TTS ปกติของ OpenClaw จะพูดเข้าไปใน Meet +- `bidi` ยังพร้อมใช้เป็นโหมดสำรองของโมเดลเสียงเรียลไทม์โดยตรง +- Agent เลือกพฤติกรรมการเข้าร่วมด้วย `mode`: ใช้ `agent` สำหรับการฟัง/พูดตอบกลับแบบสด, `bidi` สำหรับเสียงเรียลไทม์โดยตรงเป็นสำรอง, หรือ `transcribe` เพื่อเข้าร่วม/ควบคุมเบราว์เซอร์โดยไม่มีสะพานพูดตอบกลับ +- การยืนยันตัวตนเริ่มจาก Google OAuth ส่วนบุคคลหรือโปรไฟล์ Chrome ที่ลงชื่อเข้าใช้อยู่แล้ว +- ไม่มีการประกาศขอความยินยอมโดยอัตโนมัติ +- แบ็กเอนด์เสียงเริ่มต้นของ Chrome คือ `BlackHole 2ch` - Chrome สามารถทำงานในเครื่องหรือบนโฮสต์ Node ที่จับคู่ไว้ -- Twilio รับหมายเลขโทรเข้า พร้อม PIN หรือชุด DTMF ที่เป็นตัวเลือกได้ แต่ไม่สามารถโทรไปยัง URL Meet ได้โดยตรง -- คำสั่ง CLI คือ `googlemeet`; `meet` สงวนไว้สำหรับเวิร์กโฟลว์การประชุมทางไกลของ agent ที่กว้างกว่า +- Twilio รับหมายเลขโทรเข้า พร้อม PIN หรือชุด DTMF ที่ไม่บังคับ; ไม่สามารถโทรไปยัง URL ของ Meet ได้โดยตรง +- คำสั่ง CLI คือ `googlemeet`; `meet` สงวนไว้สำหรับเวิร์กโฟลว์ประชุมทางไกลของ Agent ที่กว้างกว่า ## เริ่มต้นอย่างรวดเร็ว -ติดตั้ง dependency เสียงในเครื่องและกำหนดค่า provider realtime voice แบ็กเอนด์ OpenAI เป็นค่าเริ่มต้น; Google Gemini Live ก็ใช้งานได้กับ -`realtime.provider: "google"`: +ติดตั้ง dependency เสียงในเครื่องและกำหนดค่าผู้ให้บริการถอดเสียงแบบเรียลไทม์ พร้อม TTS ปกติของ OpenClaw OpenAI คือผู้ให้บริการถอดเสียงเริ่มต้น; Google Gemini Live ก็ทำงานได้ในฐานะเสียงสำรอง `bidi` แยกต่างหากด้วย `realtime.voiceProvider: "google"`: ```bash brew install blackhole-2ch sox export OPENAI_API_KEY=sk-... -# or +# only needed when realtime.voiceProvider is "google" for bidi mode export GEMINI_API_KEY=... ``` -`blackhole-2ch` ติดตั้งอุปกรณ์เสียงเสมือน `BlackHole 2ch` ตัวติดตั้งของ Homebrew -ต้องรีบูตก่อนที่ macOS จะเปิดเผยอุปกรณ์: +`blackhole-2ch` ติดตั้งอุปกรณ์เสียงเสมือน `BlackHole 2ch` ตัวติดตั้งของ Homebrew ต้องรีบูตก่อนที่ macOS จะแสดงอุปกรณ์นี้: ```bash sudo reboot @@ -54,7 +52,7 @@ system_profiler SPAudioDataType | grep -i BlackHole command -v sox ``` -เปิดใช้งาน Plugin: +เปิดใช้ Plugin: ```json5 { @@ -75,32 +73,21 @@ command -v sox openclaw googlemeet setup ``` -เอาต์พุตการตั้งค่ามีไว้ให้อ่านได้โดย agent และรับรู้โหมด รายงานโปรไฟล์ Chrome, -การปักหมุด Node และสำหรับการเข้าร่วม Chrome แบบ realtime จะรายงานสะพานเสียง -BlackHole/SoX และการตรวจ intro realtime ที่หน่วงเวลาไว้ สำหรับการเข้าร่วมแบบดูอย่างเดียว ให้ตรวจ transport เดียวกันด้วย `--mode transcribe`; โหมดนั้นข้ามข้อกำหนดเบื้องต้นของเสียง realtime -เพราะไม่ได้ฟังผ่านหรือพูดผ่านสะพาน: +เอาต์พุตการตั้งค่าถูกออกแบบให้อ่านได้โดย Agent และรับรู้โหมด มันรายงานโปรไฟล์ Chrome, การปักหมุด Node, และสำหรับการเข้าร่วม Chrome แบบเรียลไทม์ จะรายงานสะพานเสียง BlackHole/SoX และการตรวจสอบอินโทรเรียลไทม์แบบหน่วง สำหรับการเข้าร่วมแบบสังเกตอย่างเดียว ให้ตรวจสอบ transport เดียวกันด้วย `--mode transcribe`; โหมดนั้นข้ามข้อกำหนดเสียงเรียลไทม์เบื้องต้น เพราะไม่ได้ฟังผ่านหรือพูดผ่านสะพาน: ```bash openclaw googlemeet setup --transport chrome-node --mode transcribe ``` -เมื่อกำหนดค่า delegation ของ Twilio แล้ว การตั้งค่ายังรายงานด้วยว่า Plugin -`voice-call`, credential ของ Twilio และการเปิดเผย Webhook สาธารณะพร้อมหรือไม่ -ให้ถือว่าเช็กใดๆ ที่เป็น `ok: false` เป็นตัวบล็อกสำหรับ transport และโหมดที่ตรวจ -ก่อนขอให้ agent เข้าร่วม ใช้ `openclaw googlemeet setup --json` สำหรับ -สคริปต์หรือเอาต์พุตที่เครื่องอ่านได้ ใช้ `--transport chrome`, -`--transport chrome-node` หรือ `--transport twilio` เพื่อ preflight transport เฉพาะ -ก่อนที่ agent จะลองใช้ +เมื่อกำหนดค่าการมอบหมายผ่าน Twilio แล้ว การตั้งค่าจะรายงานด้วยว่า Plugin `voice-call`, ข้อมูลประจำตัว Twilio, และการเปิดเผย Webhook สาธารณะพร้อมหรือไม่ ถือว่าการตรวจสอบใดๆ ที่เป็น `ok: false` เป็นตัวบล็อกสำหรับ transport และโหมดที่ตรวจสอบ ก่อนขอให้ Agent เข้าร่วม ใช้ `openclaw googlemeet setup --json` สำหรับสคริปต์หรือเอาต์พุตที่เครื่องอ่านได้ ใช้ `--transport chrome`, `--transport chrome-node`, หรือ `--transport twilio` เพื่อ preflight transport ที่ระบุก่อนที่ Agent จะลองใช้ -สำหรับ Twilio ให้ preflight transport อย่างชัดเจนเสมอเมื่อ transport เริ่มต้น -เป็น Chrome: +สำหรับ Twilio ให้ preflight transport อย่างชัดเจนเสมอเมื่อ transport เริ่มต้นคือ Chrome: ```bash openclaw googlemeet setup --transport twilio ``` -การทำเช่นนั้นจะจับ wiring ของ `voice-call` ที่หายไป, credential ของ Twilio หรือ -การเปิดเผย Webhook ที่เข้าถึงไม่ได้ ก่อนที่ agent จะพยายามโทรเข้าการประชุม +ซึ่งจะจับการต่อสาย `voice-call` ที่ขาดหาย, ข้อมูลประจำตัว Twilio, หรือการเปิดเผย Webhook ที่เข้าถึงไม่ได้ ก่อนที่ Agent จะพยายามโทรเข้าการประชุม เข้าร่วมการประชุม: @@ -108,7 +95,7 @@ openclaw googlemeet setup --transport twilio openclaw googlemeet join https://meet.google.com/abc-defg-hij ``` -หรือให้ agent เข้าร่วมผ่านเครื่องมือ `google_meet`: +หรือให้ Agent เข้าร่วมผ่านเครื่องมือ `google_meet`: ```json { @@ -119,34 +106,23 @@ openclaw googlemeet join https://meet.google.com/abc-defg-hij } ``` -เครื่องมือ `google_meet` สำหรับ agent ยังคงพร้อมใช้งานบนโฮสต์ที่ไม่ใช่ macOS สำหรับ -โฟลว์ artifact, calendar, setup, transcribe, Twilio และ `chrome-node` การกระทำ -พูดตอบกลับด้วย Chrome ในเครื่องจะถูกบล็อกบนโฮสต์เหล่านั้น เพราะเส้นทางเสียง Chrome ที่บันเดิลอยู่ -ตอนนี้ขึ้นกับ `BlackHole 2ch` ของ macOS บน Linux ให้ใช้ `mode: "transcribe"`, -การโทรเข้า Twilio หรือโฮสต์ `chrome-node` บน macOS สำหรับการเข้าร่วม Chrome แบบพูดตอบกลับ +เครื่องมือ `google_meet` สำหรับ Agent ยังพร้อมใช้งานบนโฮสต์ที่ไม่ใช่ macOS สำหรับ artifact, ปฏิทิน, การตั้งค่า, การถอดเสียง, Twilio, และโฟลว์ `chrome-node` การกระทำพูดตอบกลับผ่าน Chrome ในเครื่องถูกบล็อกบนโฮสต์เหล่านั้น เพราะเส้นทางเสียง Chrome ที่บันเดิลมาปัจจุบันพึ่งพา `BlackHole 2ch` ของ macOS บน Linux ให้ใช้ `mode: "transcribe"`, การโทรเข้าผ่าน Twilio, หรือโฮสต์ `chrome-node` บน macOS สำหรับการเข้าร่วมแบบพูดตอบกลับผ่าน Chrome สร้างการประชุมใหม่และเข้าร่วม: ```bash -openclaw googlemeet create --transport chrome-node --mode realtime +openclaw googlemeet create --transport chrome-node --mode agent ``` -สำหรับห้องที่สร้างด้วย API ให้ใช้ Google Meet `SpaceConfig.accessType` เมื่อต้องการ -ให้นโยบายไม่ต้องเคาะของห้องชัดเจน แทนที่จะสืบทอดจากค่าเริ่มต้นของบัญชี Google: +สำหรับห้องที่สร้างผ่าน API ให้ใช้ Google Meet `SpaceConfig.accessType` เมื่อคุณต้องการให้ policy ไม่ต้องเคาะเข้าห้องของห้องนั้นชัดเจน แทนที่จะสืบทอดจากค่าเริ่มต้นของบัญชี Google: ```bash -openclaw googlemeet create --access-type OPEN --transport chrome-node --mode realtime +openclaw googlemeet create --access-type OPEN --transport chrome-node --mode agent ``` -`OPEN` อนุญาตให้ทุกคนที่มี URL Meet เข้าร่วมได้โดยไม่ต้องเคาะ `TRUSTED` อนุญาตให้ -ผู้ใช้ที่เชื่อถือได้ขององค์กรโฮสต์ ผู้ใช้ภายนอกที่ได้รับเชิญ และผู้ใช้ที่โทรเข้า -เข้าร่วมได้โดยไม่ต้องเคาะ `RESTRICTED` จำกัดการเข้าที่ไม่ต้องเคาะไว้เฉพาะผู้ได้รับเชิญ การตั้งค่าเหล่านี้ -ใช้กับเส้นทางการสร้างผ่าน Google Meet API อย่างเป็นทางการเท่านั้น ดังนั้นต้องกำหนดค่า -credential OAuth +`OPEN` อนุญาตให้ทุกคนที่มี URL ของ Meet เข้าร่วมโดยไม่ต้องเคาะ `TRUSTED` อนุญาตให้ผู้ใช้ที่เชื่อถือได้ขององค์กรโฮสต์, ผู้ใช้ภายนอกที่ได้รับเชิญ, และผู้ใช้ที่โทรเข้าเข้าร่วมโดยไม่ต้องเคาะ `RESTRICTED` จำกัดการเข้าห้องแบบไม่ต้องเคาะไว้เฉพาะผู้ได้รับเชิญ การตั้งค่าเหล่านี้ใช้กับเส้นทางการสร้างผ่าน Google Meet API อย่างเป็นทางการเท่านั้น ดังนั้นต้องกำหนดค่าข้อมูลประจำตัว OAuth -หากคุณยืนยันตัวตน Google Meet ก่อนที่ตัวเลือกนี้จะพร้อมใช้งาน ให้รัน -`openclaw googlemeet auth login --json` อีกครั้งหลังเพิ่ม scope -`meetings.space.settings` ลงในหน้าจอความยินยอม Google OAuth ของคุณ +หากคุณยืนยันตัวตน Google Meet ก่อนที่ตัวเลือกนี้จะพร้อมใช้งาน ให้รัน `openclaw googlemeet auth login --json` อีกครั้งหลังเพิ่ม scope `meetings.space.settings` ลงในหน้าจอขอความยินยอม Google OAuth ของคุณ สร้างเฉพาะ URL โดยไม่เข้าร่วม: @@ -156,83 +132,38 @@ openclaw googlemeet create --no-join `googlemeet create` มีสองเส้นทาง: -- สร้างด้วย API: ใช้เมื่อมีการกำหนดค่า credential Google Meet OAuth นี่คือ - เส้นทางที่กำหนดผลได้แน่นอนที่สุดและไม่ขึ้นกับสถานะ UI ของเบราว์เซอร์ -- fallback ของเบราว์เซอร์: ใช้เมื่อไม่มี credential OAuth OpenClaw ใช้ Node Chrome - ที่ปักหมุดไว้ เปิด `https://meet.google.com/new` รอให้ Google - redirect ไปยัง URL โค้ดการประชุมจริง แล้วส่ง URL นั้นกลับ เส้นทางนี้ต้องการ - ให้โปรไฟล์ Chrome ของ OpenClaw บน Node ลงชื่อเข้าใช้ Google อยู่แล้ว - ระบบอัตโนมัติของเบราว์เซอร์จัดการพรอมป์ไมโครโฟนครั้งแรกของ Meet เอง; พรอมป์นั้น - ไม่ถือเป็นความล้มเหลวในการเข้าสู่ระบบ Google - โฟลว์ join และ create ยังพยายามใช้แท็บ Meet ที่มีอยู่ซ้ำก่อนเปิดแท็บใหม่ด้วย - การจับคู่จะไม่สนใจ query string ของ URL ที่ไม่เป็นอันตราย เช่น `authuser` ดังนั้น - การลองใหม่ของ agent ควรโฟกัสการประชุมที่เปิดอยู่แล้ว แทนที่จะสร้างแท็บ Chrome ที่สอง +- สร้างผ่าน API: ใช้เมื่อมีการกำหนดค่าข้อมูลประจำตัว Google Meet OAuth เส้นทางนี้กำหนดผลได้แน่นอนที่สุด และไม่พึ่งพาสถานะ UI ของเบราว์เซอร์ +- สำรองผ่านเบราว์เซอร์: ใช้เมื่อไม่มีข้อมูลประจำตัว OAuth OpenClaw ใช้ Node ของ Chrome ที่ปักหมุดไว้ เปิด `https://meet.google.com/new` รอให้ Google เปลี่ยนเส้นทางไปยัง URL รหัสการประชุมจริง แล้วส่ง URL นั้นกลับ เส้นทางนี้ต้องให้โปรไฟล์ Chrome ของ OpenClaw บน Node ลงชื่อเข้าใช้ Google อยู่แล้ว ระบบอัตโนมัติของเบราว์เซอร์จัดการพรอมป์ไมโครโฟนครั้งแรกของ Meet เอง; พรอมป์นั้นไม่ถือเป็นความล้มเหลวในการเข้าสู่ระบบ Google + โฟลว์เข้าร่วมและสร้างยังพยายามนำแท็บ Meet ที่มีอยู่กลับมาใช้ก่อนเปิดแท็บใหม่ด้วย การจับคู่จะละเว้น query string ของ URL ที่ไม่เป็นอันตราย เช่น `authuser` ดังนั้นการลองซ้ำของ Agent ควรโฟกัสการประชุมที่เปิดอยู่แล้วแทนที่จะสร้างแท็บ Chrome ที่สอง -เอาต์พุตของคำสั่ง/เครื่องมือมีฟิลด์ `source` (`api` หรือ `browser`) เพื่อให้ agents -อธิบายได้ว่าใช้เส้นทางใด `create` จะเข้าร่วมการประชุมใหม่โดยค่าเริ่มต้นและ -ส่งกลับ `joined: true` พร้อม session การเข้าร่วม หากต้องการสร้างเฉพาะ URL ให้ใช้ -`create --no-join` ใน CLI หรือส่ง `"join": false` ไปยังเครื่องมือ +เอาต์พุตคำสั่ง/เครื่องมือมีฟิลด์ `source` (`api` หรือ `browser`) เพื่อให้ Agent อธิบายได้ว่าใช้เส้นทางใด โดยค่าเริ่มต้น `create` จะเข้าร่วมการประชุมใหม่และส่งกลับ `joined: true` พร้อม session การเข้าร่วม หากต้องการสร้างเฉพาะ URL ให้ใช้ `create --no-join` บน CLI หรือส่ง `"join": false` ให้เครื่องมือ -หรือบอก agent ว่า: "Create a Google Meet, join it with realtime voice, and send -me the link." agent ควรเรียก `google_meet` ด้วย `action: "create"` แล้ว -แชร์ `meetingUri` ที่ส่งกลับมา +หรือบอก Agent ว่า: "สร้าง Google Meet, เข้าร่วมด้วยโหมดพูดตอบกลับของ Agent, แล้วส่งลิงก์ให้ฉัน" Agent ควรเรียก `google_meet` ด้วย `action: "create"` แล้วแชร์ `meetingUri` ที่ส่งกลับมา ```json { "action": "create", "transport": "chrome-node", - "mode": "realtime" + "mode": "agent" } ``` -สำหรับการเข้าร่วมแบบดูอย่างเดียว/ควบคุมเบราว์เซอร์ ให้ตั้งค่า `"mode": "transcribe"` โหมดนั้น -จะไม่เริ่มสะพาน realtime voice แบบสองทาง ไม่ต้องใช้ BlackHole หรือ SoX -และจะไม่พูดตอบกลับเข้าไปในการประชุม การเข้าร่วม Chrome ในโหมดนี้ยังหลีกเลี่ยง -การให้สิทธิ์ไมโครโฟน/กล้องของ OpenClaw และหลีกเลี่ยงเส้นทาง **Use -microphone** ของ Meet หาก Meet แสดง interstitial สำหรับเลือกเสียง ระบบอัตโนมัติจะพยายาม -ใช้เส้นทางไม่มีไมโครโฟน และมิฉะนั้นจะรายงานการกระทำด้วยตนเองแทนการเปิด -ไมโครโฟนในเครื่อง ในโหมด transcribe, transport Chrome ที่จัดการแล้วยังติดตั้ง -ตัวสังเกตคำบรรยาย Meet แบบ best-effort ด้วย `googlemeet status --json` และ -`googlemeet doctor` แสดง `captioning`, `captionsEnabledAttempted`, -`transcriptLines`, `lastCaptionAt`, `lastCaptionSpeaker`, `lastCaptionText`, -และ tail `recentTranscript` แบบสั้น เพื่อให้ operators ทราบได้ว่าเบราว์เซอร์ -เข้าร่วมสายแล้วหรือไม่ และคำบรรยาย Meet กำลังสร้างข้อความหรือไม่ -ใช้ `openclaw googlemeet test-listen --transport chrome-node` เมื่อ -คุณต้องการ probe แบบใช่/ไม่ใช่: คำสั่งนี้เข้าร่วมในโหมด transcribe รอการเคลื่อนไหวของคำบรรยายหรือ -transcript ใหม่ และส่งกลับ `listenVerified`, `listenTimedOut`, ฟิลด์การกระทำด้วยตนเอง -และสถานะคำบรรยายล่าสุด +สำหรับการเข้าร่วมแบบสังเกตอย่างเดียว/ควบคุมเบราว์เซอร์ ให้ตั้ง `"mode": "transcribe"` ซึ่งจะไม่เริ่มสะพานเสียงเรียลไทม์แบบสองทาง, ไม่ต้องใช้ BlackHole หรือ SoX, และจะไม่พูดตอบกลับเข้าไปในการประชุม การเข้าร่วมผ่าน Chrome ในโหมดนี้ยังหลีกเลี่ยงการให้สิทธิ์ไมโครโฟน/กล้องของ OpenClaw และหลีกเลี่ยงเส้นทาง **ใช้ไมโครโฟน** ของ Meet หาก Meet แสดง interstitial สำหรับการเลือกเสียง ระบบอัตโนมัติจะลองเส้นทางไม่ใช้ไมโครโฟน และถ้าไม่ได้ก็รายงานการกระทำด้วยตนเองแทนการเปิดไมโครโฟนในเครื่อง ในโหมด transcribe, managed Chrome transports ยังติดตั้งตัวสังเกตคำบรรยาย Meet แบบ best-effort ด้วย `googlemeet status --json` และ `googlemeet doctor` แสดง `captioning`, `captionsEnabledAttempted`, `transcriptLines`, `lastCaptionAt`, `lastCaptionSpeaker`, `lastCaptionText`, และส่วนท้าย `recentTranscript` สั้นๆ เพื่อให้ผู้ปฏิบัติการบอกได้ว่าเบราว์เซอร์เข้าร่วมสายแล้วหรือไม่ และคำบรรยาย Meet กำลังสร้างข้อความหรือไม่ +ใช้ `openclaw googlemeet test-listen --transport chrome-node` เมื่อต้องการ probe แบบใช่/ไม่ใช่: มันเข้าร่วมในโหมด transcribe, รอคำบรรยายสดหรือการเปลี่ยนแปลง transcript ใหม่, และส่งกลับ `listenVerified`, `listenTimedOut`, ฟิลด์การกระทำด้วยตนเอง, และสถานะคำบรรยายล่าสุด -ระหว่าง session realtime, สถานะ `google_meet` มีสุขภาพของเบราว์เซอร์และสะพานเสียง -เช่น `inCall`, `manualActionRequired`, `providerConnected`, -`realtimeReady`, `audioInputActive`, `audioOutputActive`, timestamp อินพุต/เอาต์พุตล่าสุด, -ตัวนับไบต์ และสถานะสะพานปิด หากพรอมป์หน้า Meet ที่ปลอดภัย -ปรากฏขึ้น ระบบอัตโนมัติของเบราว์เซอร์จะจัดการเมื่อทำได้ การเข้าสู่ระบบ การอนุญาตจากโฮสต์ และ -พรอมป์สิทธิ์ของเบราว์เซอร์/OS จะถูกรายงานเป็นการกระทำด้วยตนเองพร้อมเหตุผลและ -ข้อความให้ agent ถ่ายทอด Managed Chrome sessions จะปล่อย intro หรือ -วลีทดสอบหลังจากสุขภาพของเบราว์เซอร์รายงาน `inCall: true` เท่านั้น; มิฉะนั้นสถานะจะรายงาน -`speechReady: false` และความพยายามพูดจะถูกบล็อก แทนที่จะแกล้งว่า -agent พูดเข้าไปในการประชุมแล้ว +ระหว่าง session เรียลไทม์ สถานะ `google_meet` มีสถานะสุขภาพของเบราว์เซอร์และสะพานเสียง เช่น `inCall`, `manualActionRequired`, `providerConnected`, `realtimeReady`, `audioInputActive`, `audioOutputActive`, timestamp อินพุต/เอาต์พุตล่าสุด, ตัวนับ byte, และสถานะสะพานปิด หากพรอมป์หน้า Meet ที่ปลอดภัยปรากฏขึ้น ระบบอัตโนมัติของเบราว์เซอร์จะจัดการเมื่อทำได้ การเข้าสู่ระบบ, การรับเข้าห้องโดยโฮสต์, และพรอมป์สิทธิ์ของเบราว์เซอร์/OS จะถูกรายงานเป็นการกระทำด้วยตนเองพร้อมเหตุผลและข้อความให้ Agent ถ่ายทอด Managed Chrome sessions จะส่งอินโทรหรือวลีทดสอบออกมาเฉพาะหลังจากสถานะสุขภาพของเบราว์เซอร์รายงาน `inCall: true`; มิฉะนั้นสถานะจะรายงาน `speechReady: false` และบล็อกความพยายามพูด แทนการแสร้งว่า Agent ได้พูดเข้าไปในการประชุมแล้ว -การเข้าร่วม Chrome ในเครื่องใช้โปรไฟล์เบราว์เซอร์ OpenClaw ที่ลงชื่อเข้าใช้แล้ว โหมด Realtime -ต้องใช้ `BlackHole 2ch` สำหรับเส้นทางไมโครโฟน/ลำโพงที่ OpenClaw ใช้ สำหรับ -เสียงสองทางที่สะอาด ให้ใช้อุปกรณ์เสมือนแยกกันหรือกราฟแบบ Loopback; อุปกรณ์ -BlackHole เดียวเพียงพอสำหรับ smoke test แรก แต่อาจเกิดเสียงสะท้อน +การเข้าร่วมผ่าน Chrome ในเครื่องใช้โปรไฟล์เบราว์เซอร์ OpenClaw ที่ลงชื่อเข้าใช้แล้ว โหมดเรียลไทม์ต้องใช้ `BlackHole 2ch` สำหรับเส้นทางไมโครโฟน/ลำโพงที่ OpenClaw ใช้ เพื่อเสียงสองทางที่สะอาด ให้ใช้อุปกรณ์เสมือนแยกกันหรือกราฟแบบ Loopback; อุปกรณ์ BlackHole เดียวเพียงพอสำหรับ smoke test แรก แต่อาจเกิดเสียงสะท้อน -### Gateway ในเครื่อง + Parallels Chrome +### Gateway ในเครื่อง + Chrome บน Parallels -คุณ **ไม่** จำเป็นต้องมี OpenClaw Gateway เต็มรูปแบบหรือคีย์ model API ภายใน macOS VM -เพียงเพื่อให้ VM เป็นเจ้าของ Chrome ให้รัน Gateway และ agent ในเครื่อง แล้วรัน -โฮสต์ Node ใน VM เปิดใช้งาน Plugin ที่บันเดิลมากับ VM หนึ่งครั้ง เพื่อให้ Node -ประกาศคำสั่ง Chrome: +คุณ **ไม่** จำเป็นต้องมี OpenClaw Gateway เต็มรูปแบบหรือคีย์ API ของโมเดลภายใน VM macOS เพียงเพื่อให้ VM เป็นเจ้าของ Chrome ให้รัน Gateway และ Agent ในเครื่อง แล้วรันโฮสต์ Node ใน VM เปิดใช้ Plugin ที่บันเดิลมาใน VM หนึ่งครั้ง เพื่อให้ Node โฆษณาคำสั่ง Chrome: -สิ่งที่รันอยู่ที่ไหน: +สิ่งที่รันในแต่ละที่: -- โฮสต์ Gateway: OpenClaw Gateway, workspace ของ agent, คีย์ model/API, provider realtime - และ config ของ Plugin Google Meet -- Parallels macOS VM: OpenClaw CLI/โฮสต์ Node, Google Chrome, SoX, BlackHole 2ch, - และโปรไฟล์ Chrome ที่ลงชื่อเข้าใช้ Google -- ไม่จำเป็นใน VM: บริการ Gateway, config ของ agent, คีย์ OpenAI/GPT หรือการตั้งค่า - provider model +- โฮสต์ Gateway: OpenClaw Gateway, workspace ของ Agent, คีย์โมเดล/API, ผู้ให้บริการเรียลไทม์, และ config ของ Plugin Google Meet +- VM macOS ของ Parallels: OpenClaw CLI/โฮสต์ Node, Google Chrome, SoX, BlackHole 2ch, และโปรไฟล์ Chrome ที่ลงชื่อเข้าใช้ Google +- ไม่จำเป็นใน VM: บริการ Gateway, config ของ Agent, คีย์ OpenAI/GPT, หรือการตั้งค่าผู้ให้บริการโมเดล ติดตั้ง dependency ของ VM: @@ -240,20 +171,20 @@ BlackHole เดียวเพียงพอสำหรับ smoke test แ brew install blackhole-2ch sox ``` -รีบูต VM หลังติดตั้ง BlackHole เพื่อให้ macOS เปิดเผย `BlackHole 2ch`: +รีบูต VM หลังติดตั้ง BlackHole เพื่อให้ macOS แสดง `BlackHole 2ch`: ```bash sudo reboot ``` -หลังรีบูต ให้ตรวจสอบว่า VM เห็นอุปกรณ์เสียงและคำสั่ง SoX ได้: +หลังรีบูต ให้ตรวจสอบว่า VM เห็นอุปกรณ์เสียงและคำสั่ง SoX: ```bash system_profiler SPAudioDataType | grep -i BlackHole command -v sox ``` -ติดตั้งหรืออัปเดต OpenClaw ใน VM แล้วเปิดใช้งาน Plugin ที่บันเดิลไว้ที่นั่น: +ติดตั้งหรืออัปเดต OpenClaw ใน VM แล้วเปิดใช้ Plugin ที่บันเดิลมาที่นั่น: ```bash openclaw plugins enable google-meet @@ -265,8 +196,7 @@ openclaw plugins enable google-meet openclaw node run --host --port 18789 --display-name parallels-macos ``` -หาก `` เป็น IP บน LAN และคุณไม่ได้ใช้ TLS, Node จะปฏิเสธ -WebSocket plaintext เว้นแต่คุณจะ opt in สำหรับเครือข่ายส่วนตัวที่เชื่อถือได้นั้น: +หาก `` เป็น IP ของ LAN และคุณไม่ได้ใช้ TLS, Node จะปฏิเสธ WebSocket แบบ plaintext เว้นแต่คุณจะยินยอมสำหรับเครือข่ายส่วนตัวที่เชื่อถือได้นั้น: ```bash OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1 \ @@ -281,9 +211,7 @@ OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1 \ openclaw node restart ``` -`OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1` เป็น process environment ไม่ใช่การตั้งค่า -`openclaw.json` `openclaw node install` จะจัดเก็บไว้ใน environment ของ LaunchAgent -เมื่อมีอยู่ในคำสั่งติดตั้ง +`OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1` คือ environment ของ process ไม่ใช่การตั้งค่า `openclaw.json` `openclaw node install` จะเก็บค่าไว้ใน environment ของ LaunchAgent เมื่อมีค่านี้อยู่ในคำสั่งติดตั้ง อนุมัติ Node จากโฮสต์ Gateway: @@ -292,8 +220,7 @@ openclaw devices list openclaw devices approve ``` -ยืนยันว่า Gateway เห็น Node และ Node ประกาศทั้ง `googlemeet.chrome` -และ capability ของเบราว์เซอร์/`browser.proxy`: +ยืนยันว่า Gateway เห็น Node และ Node โฆษณาทั้ง `googlemeet.chrome` และความสามารถของเบราว์เซอร์/`browser.proxy`: ```bash openclaw nodes status @@ -335,83 +262,82 @@ openclaw nodes status openclaw googlemeet join https://meet.google.com/abc-defg-hij ``` -หรือขอให้ agent ใช้เครื่องมือ `google_meet` พร้อม `transport: "chrome-node"` +หรือขอให้ Agent ใช้เครื่องมือ `google_meet` ด้วย `transport: "chrome-node"` -สำหรับ smoke test แบบคำสั่งเดียวที่สร้างหรือใช้ session ซ้ำ พูดวลีที่รู้ล่วงหน้า -และพิมพ์สุขภาพ session: +สำหรับ smoke test คำสั่งเดียวที่สร้างหรือนำ session กลับมาใช้, พูดวลีที่รู้ล่วงหน้า, และพิมพ์สถานะสุขภาพของ session: ```bash openclaw googlemeet test-speech https://meet.google.com/abc-defg-hij ``` -ระหว่างการเข้าร่วมแบบเรียลไทม์ ระบบอัตโนมัติของเบราว์เซอร์ OpenClaw จะกรอกชื่อผู้เข้าร่วม กด -เข้าร่วม/ขอเข้าร่วม และยอมรับตัวเลือก "ใช้ไมโครโฟน" เมื่อใช้งาน Meet ครั้งแรก หาก -พรอมป์นั้นปรากฏขึ้น ระหว่างการเข้าร่วมแบบสังเกตการณ์อย่างเดียวหรือการสร้างการประชุมผ่านเบราว์เซอร์เท่านั้น ระบบจะ -ดำเนินการผ่านพรอมป์เดียวกันต่อไปโดยไม่ใช้ไมโครโฟน เมื่อมีตัวเลือกนั้นให้ใช้ -หากโปรไฟล์เบราว์เซอร์ยังไม่ได้ลงชื่อเข้าใช้, Meet กำลังรอการอนุมัติจากโฮสต์, +ระหว่างการเข้าร่วมแบบเรียลไทม์ ระบบอัตโนมัติของเบราว์เซอร์ OpenClaw จะกรอกชื่อผู้เข้าร่วม คลิก +Join/Ask to join และยอมรับตัวเลือก "Use microphone" ครั้งแรกของ Meet เมื่อ +พรอมป์นั้นปรากฏ ระหว่างการเข้าร่วมแบบสังเกตการณ์อย่างเดียวหรือการสร้างการประชุมด้วยเบราว์เซอร์เท่านั้น ระบบจะ +ดำเนินการต่อผ่านพรอมป์เดียวกันโดยไม่ใช้ไมโครโฟนเมื่อมีตัวเลือกนั้นให้ใช้ +หากโปรไฟล์เบราว์เซอร์ไม่ได้ลงชื่อเข้าใช้, Meet กำลังรอการอนุมัติจากโฮสต์, Chrome ต้องการสิทธิ์ไมโครโฟน/กล้องสำหรับการเข้าร่วมแบบเรียลไทม์ หรือ Meet ค้างอยู่ -ที่พรอมป์ซึ่งระบบอัตโนมัติแก้ไขไม่ได้ ผลลัพธ์ join/test-speech จะรายงาน +ที่พรอมป์ซึ่งระบบอัตโนมัติไม่สามารถจัดการได้ ผลลัพธ์ join/test-speech จะรายงาน `manualActionRequired: true` พร้อม `manualActionReason` และ -`manualActionMessage` เอเจนต์ควรหยุดลองเข้าร่วมซ้ำ รายงานข้อความที่ตรงนั้น +`manualActionMessage` Agents ควรหยุดลองเข้าร่วมซ้ำ รายงานข้อความนั้นตามจริง พร้อม `browserUrl`/`browserTitle` ปัจจุบัน และลองใหม่เฉพาะหลังจาก -ดำเนินการด้วยตนเองในเบราว์เซอร์เสร็จแล้วเท่านั้น +การดำเนินการด้วยตนเองในเบราว์เซอร์เสร็จสมบูรณ์แล้ว -หากละเว้น `chromeNode.node` OpenClaw จะเลือกอัตโนมัติเฉพาะเมื่อมี Node ที่เชื่อมต่ออยู่ -เพียงหนึ่ง Node ที่ประกาศทั้ง `googlemeet.chrome` และการควบคุมเบราว์เซอร์ หาก -มี Node ที่รองรับหลาย Node เชื่อมต่ออยู่ ให้ตั้งค่า `chromeNode.node` เป็นรหัส Node, +หากละเว้น `chromeNode.node` OpenClaw จะเลือกอัตโนมัติเฉพาะเมื่อมี +Node ที่เชื่อมต่ออยู่เพียงหนึ่งรายการซึ่งประกาศทั้ง `googlemeet.chrome` และการควบคุมเบราว์เซอร์ หาก +มี Node ที่รองรับหลายรายการเชื่อมต่ออยู่ ให้ตั้ง `chromeNode.node` เป็น id ของ Node, ชื่อที่แสดง หรือ IP ระยะไกล -การตรวจสอบความล้มเหลวที่พบบ่อย: +การตรวจสอบความล้มเหลวทั่วไป: - `Configured Google Meet node ... is not usable: offline`: Node ที่ปักหมุดไว้เป็น - ที่รู้จักของ Gateway แต่ไม่พร้อมใช้งาน เอเจนต์ควรถือว่า Node นั้นเป็น - สถานะวินิจฉัย ไม่ใช่โฮสต์ Chrome ที่ใช้ได้ และรายงานตัวบล็อกการตั้งค่า - แทนที่จะถอยกลับไปใช้ทรานสปอร์ตอื่น เว้นแต่ผู้ใช้จะขอให้ทำเช่นนั้น + ที่รู้จักของ Gateway แต่ไม่พร้อมใช้งาน Agents ควรมอง Node นั้นเป็น + สถานะวินิจฉัย ไม่ใช่เป็นโฮสต์ Chrome ที่ใช้งานได้ และรายงานตัวขัดขวางการตั้งค่า + แทนการถอยไปใช้การรับส่งอื่น เว้นแต่ผู้ใช้ขอไว้เช่นนั้น - `No connected Google Meet-capable node`: เริ่ม `openclaw node run` ใน VM, - อนุมัติการจับคู่ และตรวจสอบให้แน่ใจว่าได้รัน `openclaw plugins enable google-meet` และ - `openclaw plugins enable browser` ใน VM แล้ว ยืนยันด้วยว่า - โฮสต์ Gateway อนุญาตคำสั่ง Node ทั้งสองรายการด้วย + อนุมัติการจับคู่ และตรวจสอบให้แน่ใจว่าได้เรียกใช้ `openclaw plugins enable google-meet` และ + `openclaw plugins enable browser` ใน VM แล้ว และยืนยันว่าโฮสต์ + Gateway อนุญาตคำสั่ง Node ทั้งสองด้วย `gateway.nodes.allowCommands: ["googlemeet.chrome", "browser.proxy"]` - `BlackHole 2ch audio device not found`: ติดตั้ง `blackhole-2ch` บนโฮสต์ - ที่กำลังตรวจสอบและรีบูตก่อนใช้เสียง Chrome ภายในเครื่อง + ที่กำลังตรวจสอบ แล้วรีบูตก่อนใช้เสียง Chrome ภายในเครื่อง - `BlackHole 2ch audio device not found on the node`: ติดตั้ง `blackhole-2ch` - ใน VM และรีบูต VM + ใน VM แล้วรีบูต VM - Chrome เปิดขึ้นแต่เข้าร่วมไม่ได้: ลงชื่อเข้าใช้โปรไฟล์เบราว์เซอร์ภายใน VM หรือ - คงค่า `chrome.guestName` ไว้สำหรับการเข้าร่วมแบบแขก การเข้าร่วมอัตโนมัติแบบแขกใช้ระบบอัตโนมัติ - ของเบราว์เซอร์ OpenClaw ผ่านพร็อกซีเบราว์เซอร์ของ Node ตรวจสอบให้แน่ใจว่าคอนฟิกเบราว์เซอร์ - ของ Node ชี้ไปยังโปรไฟล์ที่คุณต้องการ เช่น - `browser.defaultProfile: "user"` หรือโปรไฟล์เซสชันที่มีอยู่และตั้งชื่อไว้ + ตั้งค่า `chrome.guestName` ไว้สำหรับการเข้าร่วมในฐานะแขก การเข้าร่วมอัตโนมัติแบบแขกใช้ระบบอัตโนมัติของ + เบราว์เซอร์ OpenClaw ผ่านพร็อกซีเบราว์เซอร์ของ Node ตรวจสอบให้แน่ใจว่าคอนฟิกเบราว์เซอร์ของ Node + ชี้ไปยังโปรไฟล์ที่คุณต้องการ เช่น + `browser.defaultProfile: "user"` หรือโปรไฟล์เซสชันที่มีอยู่แบบมีชื่อ - แท็บ Meet ซ้ำ: เปิดใช้ `chrome.reuseExistingTab: true` ไว้ OpenClaw - จะเปิดใช้งานแท็บที่มีอยู่สำหรับ URL Meet เดียวกันก่อนเปิดแท็บใหม่ และ - การสร้างการประชุมผ่านเบราว์เซอร์จะใช้แท็บ `https://meet.google.com/new` - ที่กำลังดำเนินอยู่หรือแท็บพรอมป์บัญชี Google ก่อนเปิดอีกแท็บหนึ่ง -- ไม่มีเสียง: ใน Meet ให้กำหนดเส้นทางเสียงไมโครโฟน/ลำโพงผ่านเส้นทางอุปกรณ์เสียงเสมือน + จะเปิดใช้งานแท็บที่มีอยู่สำหรับ Meet URL เดียวกันก่อนเปิดแท็บใหม่ และ + การสร้างการประชุมในเบราว์เซอร์จะใช้แท็บ `https://meet.google.com/new` + ที่กำลังดำเนินอยู่หรือแท็บพรอมป์บัญชี Google เดิมก่อนเปิดอีกแท็บ +- ไม่มีเสียง: ใน Meet ให้กำหนดเส้นทางไมโครโฟน/ลำโพงผ่านพาธอุปกรณ์เสียงเสมือน ที่ OpenClaw ใช้ ใช้อุปกรณ์เสมือนแยกกันหรือการกำหนดเส้นทางแบบ Loopback - เพื่อเสียงสองทิศทางที่สะอาด + เพื่อเสียงสองทางที่สะอาด ## หมายเหตุการติดตั้ง -ค่าเริ่มต้นของการตอบกลับเสียง Chrome ใช้เครื่องมือภายนอกสองรายการ: +ค่าเริ่มต้นการพูดตอบกลับของ Chrome ใช้เครื่องมือภายนอกสองรายการ: - `sox`: ยูทิลิตีเสียงแบบบรรทัดคำสั่ง Plugin ใช้คำสั่งอุปกรณ์ CoreAudio - อย่างชัดเจนสำหรับบริดจ์เสียง PCM16 24 kHz เริ่มต้น -- `blackhole-2ch`: ไดรเวอร์เสียงเสมือนของ macOS สร้างอุปกรณ์เสียง `BlackHole 2ch` + แบบชัดเจนสำหรับบริดจ์เสียง PCM16 24 kHz เริ่มต้น +- `blackhole-2ch`: ไดรเวอร์เสียงเสมือนของ macOS โดยจะสร้างอุปกรณ์เสียง `BlackHole 2ch` ที่ Chrome/Meet สามารถกำหนดเส้นทางผ่านได้ -OpenClaw ไม่ได้รวมแพ็กเกจใดแพ็กเกจหนึ่งไว้หรือแจกจ่ายต่อ เอกสารขอให้ผู้ใช้ -ติดตั้งเป็น dependency ของโฮสต์ผ่าน Homebrew SoX อยู่ภายใต้สัญญาอนุญาต +OpenClaw ไม่ได้บันเดิลหรือแจกจ่ายแพ็กเกจใดแพ็กเกจหนึ่ง เอกสารขอให้ผู้ใช้ +ติดตั้งเป็น dependency ของโฮสต์ผ่าน Homebrew SoX ใช้ไลเซนส์ `LGPL-2.0-only AND GPL-2.0-only`; BlackHole เป็น GPL-3.0 หากคุณสร้าง -ตัวติดตั้งหรือแอปพลายแอนซ์ที่รวม BlackHole กับ OpenClaw ให้ตรวจสอบข้อกำหนดสัญญาอนุญาต -ต้นทางของ BlackHole หรือขอใบอนุญาตแยกต่างหากจาก Existential Audio +ตัวติดตั้งหรือ appliance ที่บันเดิล BlackHole กับ OpenClaw ให้ตรวจสอบข้อกำหนดไลเซนส์ +ต้นน้ำของ BlackHole หรือขอไลเซนส์แยกจาก Existential Audio -## ทรานสปอร์ต +## การรับส่ง ### Chrome -ทรานสปอร์ต Chrome เปิด URL Meet ผ่านการควบคุมเบราว์เซอร์ของ OpenClaw และเข้าร่วม -ในฐานะโปรไฟล์เบราว์เซอร์ OpenClaw ที่ลงชื่อเข้าใช้แล้ว บน macOS, Plugin จะตรวจสอบ -`BlackHole 2ch` ก่อนเปิดใช้งาน หากมีการคอนฟิกไว้ ระบบจะรันคำสั่งตรวจสุขภาพบริดจ์เสียง -และคำสั่งเริ่มต้นก่อนเปิด Chrome ด้วย ใช้ `chrome` เมื่อ +การรับส่ง Chrome จะเปิด Meet URL ผ่านการควบคุมเบราว์เซอร์ OpenClaw และเข้าร่วม +ในฐานะโปรไฟล์เบราว์เซอร์ OpenClaw ที่ลงชื่อเข้าใช้อยู่ บน macOS Plugin จะตรวจสอบ +`BlackHole 2ch` ก่อนเปิดใช้งาน หากกำหนดค่าไว้ ระบบจะเรียกใช้คำสั่งตรวจสุขภาพ +บริดจ์เสียงและคำสั่งเริ่มต้นก่อนเปิด Chrome ด้วย ใช้ `chrome` เมื่อ Chrome/เสียงอยู่บนโฮสต์ Gateway; ใช้ `chrome-node` เมื่อ Chrome/เสียงอยู่ บน Node ที่จับคู่ไว้ เช่น Parallels macOS VM สำหรับ Chrome ภายในเครื่อง ให้เลือก โปรไฟล์ด้วย `browser.defaultProfile`; `chrome.browserProfile` จะถูกส่งไปยัง @@ -423,24 +349,24 @@ openclaw googlemeet join https://meet.google.com/abc-defg-hij --transport chrome ``` กำหนดเส้นทางเสียงไมโครโฟนและลำโพงของ Chrome ผ่านบริดจ์เสียง OpenClaw ภายในเครื่อง -หากไม่ได้ติดตั้ง `BlackHole 2ch` การเข้าร่วมจะล้มเหลวพร้อมข้อผิดพลาดการตั้งค่า -แทนที่จะเข้าร่วมแบบเงียบ ๆ โดยไม่มีเส้นทางเสียง +หากไม่ได้ติดตั้ง `BlackHole 2ch` การเข้าร่วมจะล้มเหลวด้วยข้อผิดพลาดการตั้งค่า +แทนที่จะเข้าร่วมแบบเงียบ ๆ โดยไม่มีพาธเสียง ### Twilio -ทรานสปอร์ต Twilio เป็นแผนการโทรที่เข้มงวดซึ่งมอบหมายให้ Voice Call Plugin -ไม่ได้แยกวิเคราะห์หน้า Meet เพื่อหาหมายเลขโทรศัพท์ +การรับส่ง Twilio เป็นแผนการโทรที่เข้มงวดซึ่งมอบหมายให้ Voice Call Plugin +จัดการ โดยจะไม่แยกวิเคราะห์หน้า Meet เพื่อหาหมายเลขโทรศัพท์ -ใช้ตัวเลือกนี้เมื่อไม่สามารถเข้าร่วมผ่าน Chrome ได้ หรือคุณต้องการตัวเลือกสำรอง -แบบโทรเข้า Google Meet ต้องเปิดเผยหมายเลขโทรเข้าและ PIN สำหรับ -การประชุม OpenClaw จะไม่ค้นพบข้อมูลเหล่านั้นจากหน้า Meet +ใช้สิ่งนี้เมื่อการเข้าร่วมผ่าน Chrome ไม่พร้อมใช้งาน หรือคุณต้องการทางเลือกสำรอง +การโทรเข้า Google Meet ต้องเปิดเผยหมายเลขโทรเข้าและ PIN สำหรับ +การประชุม OpenClaw จะไม่ค้นหาข้อมูลเหล่านั้นจากหน้า Meet -เปิดใช้ Voice Call Plugin บนโฮสต์ Gateway ไม่ใช่บน Node Chrome: +เปิดใช้ Voice Call Plugin บนโฮสต์ Gateway ไม่ใช่บน Chrome Node: ```json5 { plugins: { - allow: ["google-meet", "voice-call"], + allow: ["google-meet", "voice-call", "google"], entries: { "google-meet": { enabled: true, @@ -453,24 +379,44 @@ openclaw googlemeet join https://meet.google.com/abc-defg-hij --transport chrome enabled: true, config: { provider: "twilio", + inboundPolicy: "allowlist", + realtime: { + enabled: true, + provider: "google", + instructions: "Join this Google Meet as an OpenClaw agent. Be brief.", + toolPolicy: "safe-read-only", + providers: { + google: { + silenceDurationMs: 500, + startSensitivity: "high", + }, + }, + }, }, }, + google: { + enabled: true, + }, }, }, } ``` -ให้ข้อมูลรับรอง Twilio ผ่านสภาพแวดล้อมหรือคอนฟิก สภาพแวดล้อมช่วยเก็บความลับ -ไม่ให้ไปอยู่ใน `openclaw.json`: +ระบุข้อมูลประจำตัว Twilio ผ่าน environment หรือคอนฟิก Environment ช่วยเก็บ +ความลับออกจาก `openclaw.json`: ```bash export TWILIO_ACCOUNT_SID=AC... export TWILIO_AUTH_TOKEN=... export TWILIO_FROM_NUMBER=+15550001234 +export GEMINI_API_KEY=... ``` -รีสตาร์ทหรือโหลด Gateway ใหม่หลังเปิดใช้ `voice-call`; การเปลี่ยนแปลงคอนฟิก Plugin -จะไม่ปรากฏในกระบวนการ Gateway ที่กำลังรันอยู่จนกว่าจะโหลดใหม่ +ใช้ `realtime.provider: "openai"` กับ OpenAI provider Plugin และ +`OPENAI_API_KEY` แทน หากนั่นคือผู้ให้บริการเสียงเรียลไทม์ของคุณ + +รีสตาร์ตหรือโหลด Gateway ใหม่หลังเปิดใช้ `voice-call`; การเปลี่ยนแปลงคอนฟิก Plugin +จะไม่ปรากฏในโปรเซส Gateway ที่กำลังทำงานอยู่จนกว่าจะโหลดใหม่ จากนั้นตรวจสอบ: @@ -480,7 +426,7 @@ openclaw plugins list | grep -E 'google-meet|voice-call' openclaw googlemeet setup ``` -เมื่อเชื่อมต่อการมอบหมาย Twilio แล้ว `googlemeet setup` จะมีการตรวจสอบ +เมื่อการมอบหมาย Twilio เชื่อมต่อเรียบร้อยแล้ว `googlemeet setup` จะรวมการตรวจสอบ `twilio-voice-call-plugin`, `twilio-voice-call-credentials` และ `twilio-voice-call-webhook` ที่สำเร็จ @@ -502,30 +448,30 @@ openclaw googlemeet join https://meet.google.com/abc-defg-hij \ ## OAuth และ preflight -OAuth เป็นทางเลือกสำหรับการสร้างลิงก์ Meet เพราะ `googlemeet create` สามารถถอยกลับ -ไปใช้ระบบอัตโนมัติของเบราว์เซอร์ได้ คอนฟิก OAuth เมื่อคุณต้องการการสร้างผ่าน API ทางการ, -การระบุพื้นที่ หรือการตรวจ preflight ของ Meet Media API +OAuth เป็นตัวเลือกสำหรับการสร้างลิงก์ Meet เพราะ `googlemeet create` สามารถถอยไปใช้ +ระบบอัตโนมัติของเบราว์เซอร์ได้ กำหนดค่า OAuth เมื่อคุณต้องการการสร้างผ่าน API อย่างเป็นทางการ, +การแก้ไข space หรือการตรวจสอบ preflight ของ Meet Media API -การเข้าถึง Google Meet API ใช้ OAuth ของผู้ใช้: สร้างไคลเอนต์ Google Cloud OAuth, -ขอ scope ที่จำเป็น อนุญาตบัญชี Google จากนั้นเก็บ -refresh token ที่ได้ไว้ในคอนฟิก Google Meet Plugin หรือระบุ -ตัวแปรสภาพแวดล้อม `OPENCLAW_GOOGLE_MEET_*` +การเข้าถึง Google Meet API ใช้ OAuth ของผู้ใช้: สร้าง Google Cloud OAuth client, +ขอ scope ที่จำเป็น อนุญาตบัญชี Google แล้วจัดเก็บ +refresh token ที่ได้ไว้ในคอนฟิก Google Meet Plugin หรือระบุผ่าน +ตัวแปร environment `OPENCLAW_GOOGLE_MEET_*` -OAuth ไม่ได้แทนที่เส้นทางเข้าร่วมผ่าน Chrome ทรานสปอร์ต Chrome และ Chrome-node -ยังคงเข้าร่วมผ่านโปรไฟล์ Chrome ที่ลงชื่อเข้าใช้แล้ว, BlackHole/SoX และ Node ที่เชื่อมต่อ -เมื่อคุณใช้การเข้าร่วมผ่านเบราว์เซอร์ OAuth ใช้เฉพาะกับเส้นทาง Google -Meet API ทางการ: สร้างพื้นที่การประชุม, ระบุพื้นที่ และรันการตรวจ preflight -ของ Meet Media API +OAuth ไม่ได้แทนที่พาธการเข้าร่วมผ่าน Chrome การรับส่ง Chrome และ Chrome-node +ยังคงเข้าร่วมผ่านโปรไฟล์ Chrome ที่ลงชื่อเข้าใช้, BlackHole/SoX และ Node +ที่เชื่อมต่ออยู่เมื่อคุณใช้การเข้าร่วมผ่านเบราว์เซอร์ OAuth ใช้เฉพาะสำหรับพาธ Google +Meet API อย่างเป็นทางการเท่านั้น: สร้าง meeting spaces, แก้ไข spaces และเรียกใช้ +การตรวจสอบ preflight ของ Meet Media API -### สร้างข้อมูลรับรอง Google +### สร้างข้อมูลประจำตัว Google ใน Google Cloud Console: 1. สร้างหรือเลือกโปรเจกต์ Google Cloud 2. เปิดใช้ **Google Meet REST API** สำหรับโปรเจกต์นั้น -3. คอนฟิกหน้าจอความยินยอม OAuth +3. กำหนดค่าหน้าจอยินยอม OAuth - **Internal** ง่ายที่สุดสำหรับองค์กร Google Workspace - - **External** ใช้ได้กับการตั้งค่าส่วนตัว/ทดสอบ ขณะที่แอปอยู่ในสถานะ Testing + - **External** ใช้ได้กับการตั้งค่าส่วนตัว/ทดสอบ; ขณะที่แอปอยู่ใน Testing, ให้เพิ่มบัญชี Google แต่ละบัญชีที่จะอนุญาตแอปเป็นผู้ใช้ทดสอบ 4. เพิ่ม scope ที่ OpenClaw ขอ: - `https://www.googleapis.com/auth/meetings.space.created` @@ -534,7 +480,7 @@ Meet API ทางการ: สร้างพื้นที่การปร - `https://www.googleapis.com/auth/meetings.conference.media.readonly` 5. สร้าง OAuth client ID - ประเภทแอปพลิเคชัน: **Web application** - - URI เปลี่ยนเส้นทางที่อนุญาต: + - Authorized redirect URI: ```text http://localhost:8085/oauth2callback @@ -543,17 +489,17 @@ Meet API ทางการ: สร้างพื้นที่การปร 6. คัดลอก client ID และ client secret `meetings.space.created` จำเป็นสำหรับ Google Meet `spaces.create` -`meetings.space.readonly` ช่วยให้ OpenClaw ระบุ URL/รหัส Meet ไปยังพื้นที่ได้ +`meetings.space.readonly` ช่วยให้ OpenClaw แก้ไข Meet URLs/โค้ดเป็น spaces ได้ `meetings.space.settings` ช่วยให้ OpenClaw ส่งการตั้งค่า `SpaceConfig` เช่น -`accessType` ระหว่างการสร้างห้องผ่าน API -`meetings.conference.media.readonly` ใช้สำหรับ preflight ของ Meet Media API และงานสื่อ -Google อาจต้องการการลงทะเบียน Developer Preview สำหรับการใช้งาน Media API จริง -หากคุณต้องการเพียงการเข้าร่วมผ่าน Chrome บนเบราว์เซอร์ ให้ข้าม OAuth ทั้งหมด +`accessType` ระหว่างการสร้างห้องผ่าน API ได้ +`meetings.conference.media.readonly` ใช้สำหรับ preflight ของ Meet Media API และงานสื่อ; +Google อาจต้องมีการลงทะเบียน Developer Preview สำหรับการใช้ Media API จริง +หากคุณต้องการเพียงการเข้าร่วม Chrome ผ่านเบราว์เซอร์ ให้ข้าม OAuth ทั้งหมด -### ออก refresh token +### สร้าง refresh token -คอนฟิก `oauth.clientId` และเลือกคอนฟิก `oauth.clientSecret` หรือส่งผ่านเป็น -ตัวแปรสภาพแวดล้อม จากนั้นรัน: +กำหนดค่า `oauth.clientId` และ `oauth.clientSecret` หากต้องการ หรือส่งผ่านเป็น +ตัวแปร environment แล้วเรียกใช้: ```bash openclaw googlemeet auth login --json @@ -561,7 +507,7 @@ openclaw googlemeet auth login --json คำสั่งจะพิมพ์บล็อกคอนฟิก `oauth` พร้อม refresh token โดยใช้ PKCE, คอลแบ็ก localhost ที่ `http://localhost:8085/oauth2callback` และโฟลว์ -คัดลอก/วางด้วยตนเองเมื่อใช้ `--manual` +คัดลอก/วางด้วยตนเองด้วย `--manual` ตัวอย่าง: @@ -571,7 +517,7 @@ OPENCLAW_GOOGLE_MEET_CLIENT_SECRET="your-client-secret" \ openclaw googlemeet auth login --json ``` -ใช้โหมดด้วยตนเองเมื่อเบราว์เซอร์เข้าถึงคอลแบ็กภายในเครื่องไม่ได้: +ใช้โหมด manual เมื่อเบราว์เซอร์เข้าถึงคอลแบ็กภายในเครื่องไม่ได้: ```bash OPENCLAW_GOOGLE_MEET_CLIENT_ID="your-client-id" \ @@ -579,7 +525,7 @@ OPENCLAW_GOOGLE_MEET_CLIENT_SECRET="your-client-secret" \ openclaw googlemeet auth login --json --manual ``` -เอาต์พุต JSON มี: +เอาต์พุต JSON รวมถึง: ```json { @@ -594,7 +540,7 @@ openclaw googlemeet auth login --json --manual } ``` -เก็บอ็อบเจ็กต์ `oauth` ไว้ใต้คอนฟิก Google Meet Plugin: +จัดเก็บอ็อบเจกต์ `oauth` ไว้ใต้คอนฟิก Google Meet Plugin: ```json5 { @@ -615,61 +561,60 @@ openclaw googlemeet auth login --json --manual } ``` -ควรใช้ตัวแปรสภาพแวดล้อมเมื่อคุณไม่ต้องการให้ refresh token อยู่ในคอนฟิก -หากมีทั้งค่าคอนฟิกและค่าสภาพแวดล้อม Plugin จะใช้คอนฟิกก่อน -แล้วจึงใช้ค่าสภาพแวดล้อมเป็น fallback +ควรใช้ตัวแปร environment เมื่อคุณไม่ต้องการให้ refresh token อยู่ในคอนฟิก +หากมีทั้งค่าจากคอนฟิกและ environment Plugin จะเลือกคอนฟิก +ก่อน แล้วจึงใช้ environment เป็น fallback -ความยินยอม OAuth รวมการสร้างพื้นที่ Meet, สิทธิ์อ่านพื้นที่ Meet และสิทธิ์อ่านสื่อ -การประชุม Meet หากคุณยืนยันตัวตนก่อนที่การรองรับการสร้างการประชุมจะมีอยู่ -ให้รัน `openclaw googlemeet auth login --json` ใหม่ เพื่อให้ refresh token -มี scope `meetings.space.created` +การยินยอม OAuth รวมการสร้าง Meet space, สิทธิ์อ่าน Meet space และสิทธิ์อ่านสื่อ +การประชุมของ Meet หากคุณยืนยันตัวตนก่อนมีการรองรับการสร้างการประชุม +ให้เรียกใช้ `openclaw googlemeet auth login --json` อีกครั้ง เพื่อให้ refresh +token มี scope `meetings.space.created` ### ตรวจสอบ OAuth ด้วย doctor -รัน OAuth doctor เมื่อคุณต้องการตรวจสุขภาพที่รวดเร็วและไม่เปิดเผยความลับ: +เรียกใช้ OAuth doctor เมื่อคุณต้องการการตรวจสุขภาพที่รวดเร็วและไม่เปิดเผยความลับ: ```bash openclaw googlemeet doctor --oauth --json ``` -คำสั่งนี้จะไม่โหลดรันไทม์ Chrome หรือจำเป็นต้องมี Node Chrome ที่เชื่อมต่ออยู่ -จะตรวจว่ามีคอนฟิก OAuth และ refresh token สามารถออก access -token ได้ รายงาน JSON มีเฉพาะฟิลด์สถานะ เช่น `ok`, `configured`, +คำสั่งนี้ไม่โหลด Chrome runtime หรือจำเป็นต้องมี Chrome Node ที่เชื่อมต่ออยู่ +โดยตรวจสอบว่ามีคอนฟิก OAuth และ refresh token สามารถสร้าง access +token ได้ รายงาน JSON จะรวมเฉพาะฟิลด์สถานะ เช่น `ok`, `configured`, `tokenSource`, `expiresAt` และข้อความตรวจสอบ; จะไม่พิมพ์ access token, refresh token หรือ client secret -ผลลัพธ์ที่พบบ่อย: +ผลลัพธ์ทั่วไป: -| การตรวจสอบ | ความหมาย | +| การตรวจสอบ | ความหมาย | | -------------------- | --------------------------------------------------------------------------------------- | -| `oauth-config` | มี `oauth.clientId` พร้อม `oauth.refreshToken` หรือ access token ที่แคชไว้ | -| `oauth-token` | access token ที่แคชไว้ยังใช้ได้ หรือ refresh token ออก access token ใหม่ | -| `meet-spaces-get` | การตรวจสอบ `--meeting` ที่เป็นทางเลือกระบุพื้นที่ Meet ที่มีอยู่ได้ | -| `meet-spaces-create` | การตรวจสอบ `--create-space` ที่เป็นทางเลือกสร้างพื้นที่ Meet ใหม่ | +| `oauth-config` | มี `oauth.clientId` พร้อม `oauth.refreshToken` หรือโทเค็นการเข้าถึงที่แคชไว้ | +| `oauth-token` | โทเค็นการเข้าถึงที่แคชไว้ยังใช้ได้ หรือโทเค็นรีเฟรชออกโทเค็นการเข้าถึงใหม่ | +| `meet-spaces-get` | การตรวจสอบ `--meeting` แบบไม่บังคับแก้ค่าเป็น Meet space ที่มีอยู่แล้ว | +| `meet-spaces-create` | การตรวจสอบ `--create-space` แบบไม่บังคับสร้าง Meet space ใหม่ | -เพื่อพิสูจน์การเปิดใช้ Google Meet API และ scope `spaces.create` ด้วย ให้รัน -การตรวจสร้างที่มีผลข้างเคียง: +หากต้องการพิสูจน์การเปิดใช้ Google Meet API และขอบเขต `spaces.create` ด้วย ให้รันการตรวจสอบสร้างที่มีผลข้างเคียง: ```bash openclaw googlemeet doctor --oauth --create-space --json openclaw googlemeet create --no-join --json ``` -`--create-space` จะสร้าง URL Meet ชั่วคราวที่ทิ้งได้ ใช้เมื่อต้องการยืนยันว่าโปรเจกต์ Google Cloud เปิดใช้ Meet API แล้ว และบัญชีที่ได้รับอนุญาตมี scope `meetings.space.created` +`--create-space` สร้าง Meet URL ชั่วคราว ใช้เมื่อคุณต้องยืนยันว่าโปรเจกต์ Google Cloud เปิดใช้ Meet API แล้ว และบัญชีที่ได้รับอนุญาตมีขอบเขต `meetings.space.created` -เพื่อพิสูจน์สิทธิ์อ่านสำหรับพื้นที่การประชุมที่มีอยู่: +หากต้องการพิสูจน์สิทธิ์อ่านสำหรับ meeting space ที่มีอยู่: ```bash openclaw googlemeet doctor --oauth --meeting https://meet.google.com/abc-defg-hij --json openclaw googlemeet resolve-space --meeting https://meet.google.com/abc-defg-hij ``` -`doctor --oauth --meeting` และ `resolve-space` พิสูจน์สิทธิ์อ่านพื้นที่ที่มีอยู่ซึ่งบัญชี Google ที่ได้รับอนุญาตเข้าถึงได้ `403` จากการตรวจสอบเหล่านี้มักหมายความว่า Google Meet REST API ถูกปิดใช้งาน, refresh token ที่ยินยอมไว้ไม่มี scope ที่จำเป็น, หรือบัญชี Google ไม่สามารถเข้าถึงพื้นที่ Meet นั้นได้ ข้อผิดพลาด refresh-token หมายความว่าให้รัน `openclaw googlemeet auth login ---json` อีกครั้งแล้วเก็บบล็อก `oauth` ใหม่ +`doctor --oauth --meeting` และ `resolve-space` พิสูจน์สิทธิ์อ่านสำหรับ space ที่มีอยู่ซึ่งบัญชี Google ที่ได้รับอนุญาตเข้าถึงได้ ค่า `403` จากการตรวจสอบเหล่านี้มักหมายความว่า Google Meet REST API ถูกปิดใช้งาน, โทเค็นรีเฟรชที่ยินยอมไว้ไม่มีขอบเขตที่จำเป็น, หรือบัญชี Google ไม่สามารถเข้าถึง Meet space นั้นได้ ข้อผิดพลาดของโทเค็นรีเฟรชหมายความว่าให้รัน `openclaw googlemeet auth login +--json` อีกครั้งและจัดเก็บบล็อก `oauth` ใหม่ -ไม่จำเป็นต้องมีข้อมูลรับรอง OAuth สำหรับทางเลือกสำรองของเบราว์เซอร์ ในโหมดนั้น การยืนยันตัวตน Google มาจากโปรไฟล์ Chrome ที่ลงชื่อเข้าใช้บนโหนดที่เลือก ไม่ใช่จากการกำหนดค่า OpenClaw +ไม่จำเป็นต้องมีข้อมูลประจำตัว OAuth สำหรับทางเลือกสำรองของเบราว์เซอร์ ในโหมดนั้น การยืนยันตัวตน Google มาจากโปรไฟล์ Chrome ที่ลงชื่อเข้าใช้บน Node ที่เลือก ไม่ใช่จากการกำหนดค่า OpenClaw -ตัวแปรสภาพแวดล้อมเหล่านี้รองรับเป็นค่าทางเลือกสำรอง: +ยอมรับตัวแปรสภาพแวดล้อมเหล่านี้เป็นค่าทางเลือกสำรอง: - `OPENCLAW_GOOGLE_MEET_CLIENT_ID` หรือ `GOOGLE_MEET_CLIENT_ID` - `OPENCLAW_GOOGLE_MEET_CLIENT_SECRET` หรือ `GOOGLE_MEET_CLIENT_SECRET` @@ -680,19 +625,19 @@ openclaw googlemeet resolve-space --meeting https://meet.google.com/abc-defg-hij - `OPENCLAW_GOOGLE_MEET_DEFAULT_MEETING` หรือ `GOOGLE_MEET_DEFAULT_MEETING` - `OPENCLAW_GOOGLE_MEET_PREVIEW_ACK` หรือ `GOOGLE_MEET_PREVIEW_ACK` -แปลง URL Meet, รหัส, หรือ `spaces/{id}` ผ่าน `spaces.get`: +แก้ค่า Meet URL, รหัส, หรือ `spaces/{id}` ผ่าน `spaces.get`: ```bash openclaw googlemeet resolve-space --meeting https://meet.google.com/abc-defg-hij ``` -รันการตรวจสอบล่วงหน้าก่อนงานสื่อ: +รันการตรวจสอบก่อนเริ่มงานสื่อ: ```bash openclaw googlemeet preflight --meeting https://meet.google.com/abc-defg-hij ``` -แสดงรายการอาร์ติแฟกต์การประชุมและการเข้าร่วมหลังจาก Meet สร้างระเบียนการประชุมแล้ว: +แสดงรายการอาร์ทิแฟกต์การประชุมและการเข้าร่วมหลังจาก Meet สร้างระเบียนการประชุมแล้ว: ```bash openclaw googlemeet artifacts --meeting https://meet.google.com/abc-defg-hij @@ -700,9 +645,9 @@ openclaw googlemeet attendance --meeting https://meet.google.com/abc-defg-hij openclaw googlemeet export --meeting https://meet.google.com/abc-defg-hij --output ./meet-export ``` -เมื่อใช้ `--meeting` ค่า `artifacts` และ `attendance` จะใช้ระเบียนการประชุมล่าสุดตามค่าเริ่มต้น ส่ง `--all-conference-records` เมื่อต้องการทุกระเบียนที่ยังถูกเก็บไว้สำหรับการประชุมนั้น +เมื่อใช้ `--meeting`, `artifacts` และ `attendance` จะใช้ระเบียนการประชุมล่าสุดโดยค่าเริ่มต้น ส่ง `--all-conference-records` เมื่อคุณต้องการระเบียนทั้งหมดที่ยังเก็บไว้สำหรับการประชุมนั้น -การค้นหา Calendar สามารถแปลง URL การประชุมจาก Google Calendar ก่อนอ่านอาร์ติแฟกต์ Meet: +การค้นหา Calendar สามารถแก้ค่า URL การประชุมจาก Google Calendar ก่อนอ่านอาร์ทิแฟกต์ Meet: ```bash openclaw googlemeet latest --today @@ -711,10 +656,10 @@ openclaw googlemeet artifacts --event "Weekly sync" openclaw googlemeet attendance --today --format csv --output attendance.csv ``` -`--today` ค้นหาปฏิทิน `primary` ของวันนี้เพื่อหาเหตุการณ์ Calendar ที่มีลิงก์ Google Meet ใช้ `--event ` เพื่อค้นหาข้อความเหตุการณ์ที่ตรงกัน และ `--calendar ` สำหรับปฏิทินที่ไม่ใช่ปฏิทินหลัก การค้นหา Calendar ต้องมีการเข้าสู่ระบบ OAuth ใหม่ที่รวม scope อ่านอย่างเดียวสำหรับเหตุการณ์ Calendar +`--today` ค้นหาปฏิทิน `primary` ของวันนี้เพื่อหาเหตุการณ์ Calendar ที่มีลิงก์ Google Meet ใช้ `--event ` เพื่อค้นหาข้อความเหตุการณ์ที่ตรงกัน และ `--calendar ` สำหรับปฏิทินที่ไม่ใช่ปฏิทินหลัก การค้นหา Calendar ต้องใช้การเข้าสู่ระบบ OAuth ใหม่ที่รวมขอบเขตอ่านอย่างเดียวของเหตุการณ์ Calendar `calendar-events` แสดงตัวอย่างเหตุการณ์ Meet ที่ตรงกันและทำเครื่องหมายเหตุการณ์ที่ `latest`, `artifacts`, `attendance`, หรือ `export` จะเลือก -หากคุณทราบ id ระเบียนการประชุมอยู่แล้ว ให้ระบุโดยตรง: +หากคุณรู้อยู่แล้วว่าเป็นไอดีระเบียนการประชุมใด ให้ระบุโดยตรง: ```bash openclaw googlemeet latest --meeting https://meet.google.com/abc-defg-hij @@ -722,15 +667,14 @@ openclaw googlemeet artifacts --conference-record conferenceRecords/abc123 --jso openclaw googlemeet attendance --conference-record conferenceRecords/abc123 --json ``` -จบการประชุมที่ใช้งานอยู่สำหรับพื้นที่ที่สร้างด้วย API เมื่อต้องการปิดห้องหลังการโทร: +จบการประชุมที่ใช้งานอยู่สำหรับ space ที่สร้างด้วย API เมื่อคุณต้องการปิดห้องหลังการโทร: ```bash openclaw googlemeet end-active-conference https://meet.google.com/abc-defg-hij ``` -คำสั่งนี้เรียก Google Meet `spaces.endActiveConference` และต้องใช้ OAuth พร้อม scope `meetings.space.created` สำหรับพื้นที่ที่บัญชีที่ได้รับอนุญาตจัดการได้ -OpenClaw รองรับอินพุตเป็น URL Meet, รหัสการประชุม, หรือ `spaces/{id}` และแปลงเป็นทรัพยากรพื้นที่ของ API ก่อนจบการประชุมที่ใช้งานอยู่ -คำสั่งนี้แยกจาก `googlemeet leave`: `leave` หยุดการเข้าร่วมแบบ local/session ของ OpenClaw ส่วน `end-active-conference` ขอให้ Google Meet จบการประชุมที่ใช้งานอยู่สำหรับพื้นที่นั้น +คำสั่งนี้เรียก Google Meet `spaces.endActiveConference` และต้องใช้ OAuth พร้อมขอบเขต `meetings.space.created` สำหรับ space ที่บัญชีที่ได้รับอนุญาตจัดการได้ OpenClaw ยอมรับอินพุตเป็น Meet URL, รหัสการประชุม, หรือ `spaces/{id}` แล้วแก้ค่าเป็นทรัพยากร space ของ API ก่อนจบการประชุมที่ใช้งานอยู่ +คำสั่งนี้แยกจาก `googlemeet leave`: `leave` หยุดการเข้าร่วมแบบ local/session ของ OpenClaw ส่วน `end-active-conference` ขอให้ Google Meet จบการประชุมที่ใช้งานอยู่สำหรับ space เขียนรายงานที่อ่านง่าย: @@ -747,13 +691,13 @@ openclaw googlemeet export --conference-record conferenceRecords/abc123 \ --include-doc-bodies --dry-run ``` -`artifacts` ส่งคืนเมทาดาทาระเบียนการประชุมพร้อมเมทาดาทาทรัพยากรผู้เข้าร่วม, การบันทึก, ทรานสคริปต์, รายการทรานสคริปต์แบบมีโครงสร้าง, และบันทึกอัจฉริยะ เมื่อ Google เปิดเผยข้อมูลเหล่านี้สำหรับการประชุม ใช้ `--no-transcript-entries` เพื่อข้ามการค้นหารายการสำหรับการประชุมขนาดใหญ่ `attendance` ขยายผู้เข้าร่วมเป็นแถวเซสชันผู้เข้าร่วมพร้อมเวลาเห็นครั้งแรก/ครั้งล่าสุด, ระยะเวลาเซสชันรวม, แฟล็กมาสาย/ออกก่อน, และทรัพยากรผู้เข้าร่วมที่ซ้ำกันซึ่งผสานตามผู้ใช้ที่ลงชื่อเข้าใช้หรือชื่อที่แสดง ส่ง `--no-merge-duplicates` เพื่อเก็บทรัพยากรผู้เข้าร่วมดิบแยกกัน, `--late-after-minutes` เพื่อปรับการตรวจจับการมาสาย, และ `--early-before-minutes` เพื่อปรับการตรวจจับการออกก่อน +`artifacts` ส่งคืนเมตาดาต้าของระเบียนการประชุมพร้อมเมตาดาต้าทรัพยากรของผู้เข้าร่วม, การบันทึก, บทถอดเสียง, รายการบทถอดเสียงแบบมีโครงสร้าง, และบันทึกอัจฉริยะเมื่อ Google เปิดเผยให้กับการประชุมนั้น ใช้ `--no-transcript-entries` เพื่อข้ามการค้นหารายการสำหรับการประชุมขนาดใหญ่ `attendance` ขยายผู้เข้าร่วมเป็นแถวเซสชันผู้เข้าร่วมพร้อมเวลาเห็นครั้งแรก/ครั้งล่าสุด, ระยะเวลาเซสชันรวม, แฟล็กมาสาย/ออกก่อน, และรวมทรัพยากรผู้เข้าร่วมที่ซ้ำกันตามผู้ใช้ที่ลงชื่อเข้าใช้หรือชื่อที่แสดง ส่ง `--no-merge-duplicates` เพื่อแยกทรัพยากรผู้เข้าร่วมดิบไว้ต่างหาก, `--late-after-minutes` เพื่อปรับการตรวจจับมาสาย, และ `--early-before-minutes` เพื่อปรับการตรวจจับออกก่อน -`export` เขียนโฟลเดอร์ที่ประกอบด้วย `summary.md`, `attendance.csv`, `transcript.md`, `artifacts.json`, `attendance.json`, และ `manifest.json` -`manifest.json` บันทึกอินพุตที่เลือก, ตัวเลือกการส่งออก, ระเบียนการประชุม, ไฟล์เอาต์พุต, จำนวน, แหล่งที่มาของโทเค็น, เหตุการณ์ Calendar เมื่อมีการใช้, และคำเตือนการดึงข้อมูลบางส่วน ส่ง `--zip` เพื่อเขียนไฟล์เก็บถาวรแบบพกพาไว้ข้างโฟลเดอร์ด้วย ส่ง `--include-doc-bodies` เพื่อส่งออกข้อความ Google Docs ของทรานสคริปต์และบันทึกอัจฉริยะที่ลิงก์ผ่าน Google Drive `files.export`; สิ่งนี้ต้องใช้การเข้าสู่ระบบ OAuth ใหม่ที่รวม scope อ่านอย่างเดียวของ Drive Meet หากไม่ใช้ `--include-doc-bodies` การส่งออกจะรวมเฉพาะเมทาดาทา Meet และรายการทรานสคริปต์แบบมีโครงสร้างเท่านั้น หาก Google ส่งคืนความล้มเหลวของอาร์ติแฟกต์บางส่วน เช่น ข้อผิดพลาดการแสดงรายการบันทึกอัจฉริยะ, รายการทรานสคริปต์, หรือเนื้อหาเอกสาร Drive สรุปและ manifest จะเก็บคำเตือนไว้แทนที่จะทำให้การส่งออกทั้งหมดล้มเหลว -ใช้ `--dry-run` เพื่อดึงข้อมูลอาร์ติแฟกต์/การเข้าร่วมเดียวกันและพิมพ์ JSON ของ manifest โดยไม่สร้างโฟลเดอร์หรือ ZIP สิ่งนี้มีประโยชน์ก่อนเขียนการส่งออกขนาดใหญ่ หรือเมื่อเอเจนต์ต้องการเพียงจำนวน, ระเบียนที่เลือก, และคำเตือน +`export` เขียนโฟลเดอร์ที่มี `summary.md`, `attendance.csv`, `transcript.md`, `artifacts.json`, `attendance.json`, และ `manifest.json` +`manifest.json` บันทึกอินพุตที่เลือก, ตัวเลือกการส่งออก, ระเบียนการประชุม, ไฟล์เอาต์พุต, จำนวน, แหล่งที่มาของโทเค็น, เหตุการณ์ Calendar เมื่อมีการใช้, และคำเตือนการดึงข้อมูลบางส่วน ส่ง `--zip` เพื่อเขียนไฟล์เก็บถาวรแบบพกพาข้างโฟลเดอร์ด้วย ส่ง `--include-doc-bodies` เพื่อส่งออกข้อความ Google Docs ของบทถอดเสียงและบันทึกอัจฉริยะที่เชื่อมโยงผ่าน Google Drive `files.export`; สิ่งนี้ต้องใช้การเข้าสู่ระบบ OAuth ใหม่ที่รวมขอบเขตอ่านอย่างเดียวของ Drive Meet หากไม่มี `--include-doc-bodies` การส่งออกจะรวมเฉพาะเมตาดาต้า Meet และรายการบทถอดเสียงแบบมีโครงสร้างเท่านั้น หาก Google ส่งคืนความล้มเหลวของอาร์ทิแฟกต์บางส่วน เช่น ข้อผิดพลาดการแสดงรายการบันทึกอัจฉริยะ, รายการบทถอดเสียง, หรือเนื้อหาเอกสารจาก Drive สรุปและแมนิเฟสต์จะเก็บคำเตือนไว้แทนที่จะทำให้การส่งออกทั้งหมดล้มเหลว +ใช้ `--dry-run` เพื่อดึงข้อมูลอาร์ทิแฟกต์/การเข้าร่วมชุดเดียวกันและพิมพ์ JSON ของแมนิเฟสต์โดยไม่สร้างโฟลเดอร์หรือ ZIP วิธีนี้มีประโยชน์ก่อนเขียนการส่งออกขนาดใหญ่ หรือเมื่อ agent ต้องการเพียงจำนวน ระเบียนที่เลือก และคำเตือน -เอเจนต์ยังสามารถสร้างบันเดิลเดียวกันผ่านเครื่องมือ `google_meet` ได้: +agent ยังสามารถสร้างบันเดิลเดียวกันผ่านเครื่องมือ `google_meet`: ```json { @@ -765,20 +709,20 @@ openclaw googlemeet export --conference-record conferenceRecords/abc123 \ } ``` -ตั้งค่า `"dryRun": true` เพื่อส่งคืนเฉพาะ manifest การส่งออกและข้ามการเขียนไฟล์ +ตั้งค่า `"dryRun": true` เพื่อส่งคืนเฉพาะแมนิเฟสต์การส่งออกและข้ามการเขียนไฟล์ -เอเจนต์ยังสามารถสร้างห้องที่รองรับด้วย API พร้อมนโยบายการเข้าถึงที่ระบุชัดเจน: +agent ยังสามารถสร้างห้องที่หนุนด้วย API พร้อมนโยบายการเข้าถึงที่ระบุชัดเจน: ```json { "action": "create", "transport": "chrome-node", - "mode": "realtime", + "mode": "agent", "accessType": "OPEN" } ``` -และสามารถจบการประชุมที่ใช้งานอยู่สำหรับห้องที่ทราบได้: +และสามารถจบการประชุมที่ใช้งานอยู่สำหรับห้องที่รู้จักได้: ```json { @@ -787,7 +731,7 @@ openclaw googlemeet export --conference-record conferenceRecords/abc123 \ } ``` -สำหรับการตรวจสอบแบบฟังก่อน เอเจนต์ควรใช้ `test_listen` ก่อนอ้างว่าการประชุมมีประโยชน์: +สำหรับการตรวจสอบแบบฟังก่อน agent ควรใช้ `test_listen` ก่อนอ้างว่าการประชุมมีประโยชน์: ```json { @@ -798,7 +742,7 @@ openclaw googlemeet export --conference-record conferenceRecords/abc123 \ } ``` -รัน live smoke แบบมีการป้องกันกับการประชุมจริงที่ยังถูกเก็บไว้: +รัน live smoke ที่มีการป้องกันกับการประชุมจริงที่ยังเก็บไว้: ```bash OPENCLAW_LIVE_TEST=1 \ @@ -806,7 +750,7 @@ OPENCLAW_GOOGLE_MEET_LIVE_MEETING=https://meet.google.com/abc-defg-hij \ pnpm test:live -- extensions/google-meet/google-meet.live.test.ts ``` -รันโพรบเบราว์เซอร์แบบสดที่ฟังก่อนกับการประชุมซึ่งจะมีคนพูดและมีคำบรรยาย Meet พร้อมใช้งาน: +รันโพรบเบราว์เซอร์แบบฟังก่อนแบบสดกับการประชุมที่มีคนพูดและมีคำบรรยาย Meet พร้อมใช้งาน: ```bash openclaw googlemeet setup --transport chrome-node --mode transcribe @@ -815,27 +759,26 @@ openclaw googlemeet test-listen https://meet.google.com/abc-defg-hij --transport สภาพแวดล้อม live smoke: -- `OPENCLAW_LIVE_TEST=1` เปิดใช้การทดสอบสดแบบมีการป้องกัน -- `OPENCLAW_GOOGLE_MEET_LIVE_MEETING` ชี้ไปยัง URL Meet, รหัส, หรือ - `spaces/{id}` ที่ยังถูกเก็บไว้ -- `OPENCLAW_GOOGLE_MEET_CLIENT_ID` หรือ `GOOGLE_MEET_CLIENT_ID` ให้ id ไคลเอนต์ OAuth -- `OPENCLAW_GOOGLE_MEET_REFRESH_TOKEN` หรือ `GOOGLE_MEET_REFRESH_TOKEN` ให้ refresh token -- ตัวเลือกเสริม: `OPENCLAW_GOOGLE_MEET_CLIENT_SECRET`, +- `OPENCLAW_LIVE_TEST=1` เปิดใช้การทดสอบสดที่มีการป้องกัน +- `OPENCLAW_GOOGLE_MEET_LIVE_MEETING` ชี้ไปที่ Meet URL, รหัส, หรือ `spaces/{id}` ที่ยังเก็บไว้ +- `OPENCLAW_GOOGLE_MEET_CLIENT_ID` หรือ `GOOGLE_MEET_CLIENT_ID` ให้ไอดีไคลเอนต์ OAuth +- `OPENCLAW_GOOGLE_MEET_REFRESH_TOKEN` หรือ `GOOGLE_MEET_REFRESH_TOKEN` ให้โทเค็นรีเฟรช +- ไม่บังคับ: `OPENCLAW_GOOGLE_MEET_CLIENT_SECRET`, `OPENCLAW_GOOGLE_MEET_ACCESS_TOKEN`, และ `OPENCLAW_GOOGLE_MEET_ACCESS_TOKEN_EXPIRES_AT` ใช้ชื่อทางเลือกสำรองเดียวกันโดยไม่มีคำนำหน้า `OPENCLAW_` -live smoke พื้นฐานสำหรับอาร์ติแฟกต์/การเข้าร่วมต้องใช้ +live smoke พื้นฐานสำหรับอาร์ทิแฟกต์/การเข้าร่วมต้องใช้ `https://www.googleapis.com/auth/meetings.space.readonly` และ -`https://www.googleapis.com/auth/meetings.conference.media.readonly` การค้นหา Calendar ต้องใช้ `https://www.googleapis.com/auth/calendar.events.readonly` การส่งออกเนื้อหาเอกสาร Drive ต้องใช้ +`https://www.googleapis.com/auth/meetings.conference.media.readonly` การค้นหา Calendar ต้องใช้ `https://www.googleapis.com/auth/calendar.events.readonly` การส่งออกเนื้อหาเอกสารจาก Drive ต้องใช้ `https://www.googleapis.com/auth/drive.meet.readonly` -สร้างพื้นที่ Meet ใหม่: +สร้าง Meet space ใหม่: ```bash openclaw googlemeet create ``` -คำสั่งจะพิมพ์ `meeting uri` ใหม่, แหล่งที่มา, และเซสชันเข้าร่วม เมื่อมีข้อมูลรับรอง OAuth จะใช้ Google Meet API อย่างเป็นทางการ หากไม่มีข้อมูลรับรอง OAuth จะใช้โปรไฟล์เบราว์เซอร์ที่ลงชื่อเข้าใช้ของโหนด Chrome ที่ปักหมุดไว้เป็นทางเลือกสำรอง เอเจนต์สามารถใช้เครื่องมือ `google_meet` พร้อม `action: "create"` เพื่อสร้างและเข้าร่วมในขั้นตอนเดียว สำหรับการสร้างเฉพาะ URL ให้ส่ง `"join": false` +คำสั่งนี้พิมพ์ `meeting uri`, แหล่งที่มา, และเซสชันเข้าร่วมใหม่ เมื่อมีข้อมูลประจำตัว OAuth คำสั่งจะใช้ Google Meet API อย่างเป็นทางการ หากไม่มีข้อมูลประจำตัว OAuth คำสั่งจะใช้โปรไฟล์เบราว์เซอร์ที่ลงชื่อเข้าใช้ของ Node Chrome ที่ปักหมุดไว้เป็นทางเลือกสำรอง agent สามารถใช้เครื่องมือ `google_meet` พร้อม `action: "create"` เพื่อสร้างและเข้าร่วมในขั้นตอนเดียว สำหรับการสร้างเฉพาะ URL ให้ส่ง `"join": false` ตัวอย่างเอาต์พุต JSON จากทางเลือกสำรองของเบราว์เซอร์: @@ -857,7 +800,7 @@ openclaw googlemeet create } ``` -หากทางเลือกสำรองของเบราว์เซอร์พบตัวกั้นการเข้าสู่ระบบ Google หรือสิทธิ์ Meet ก่อนที่จะสร้าง URL ได้ เมธอด Gateway จะส่งคืนการตอบกลับที่ล้มเหลว และเครื่องมือ `google_meet` จะส่งคืนรายละเอียดแบบมีโครงสร้างแทนสตริงธรรมดา: +หากทางเลือกสำรองของเบราว์เซอร์เจอการเข้าสู่ระบบ Google หรือตัวขวางสิทธิ์ Meet ก่อนที่จะสร้าง URL ได้ เมธอด Gateway จะส่งคืนการตอบกลับที่ล้มเหลว และเครื่องมือ `google_meet` จะส่งคืนรายละเอียดแบบมีโครงสร้างแทนสตริงธรรมดา: ```json { @@ -875,9 +818,9 @@ openclaw googlemeet create } ``` -เมื่อเอเจนต์เห็น `manualActionRequired: true` ควรรายงาน `manualActionMessage` พร้อมบริบทโหนด/แท็บของเบราว์เซอร์ และหยุดเปิดแท็บ Meet ใหม่จนกว่าผู้ปฏิบัติการจะทำขั้นตอนในเบราว์เซอร์เสร็จ +เมื่อ agent เห็น `manualActionRequired: true` ควรรายงาน `manualActionMessage` พร้อมบริบท Node/แท็บของเบราว์เซอร์ แล้วหยุดเปิดแท็บ Meet ใหม่จนกว่าผู้ปฏิบัติการจะทำขั้นตอนในเบราว์เซอร์ให้เสร็จ -ตัวอย่างเอาต์พุต JSON จากการสร้างด้วย API: +ตัวอย่างเอาต์พุต JSON จากการสร้างผ่าน API: ```json { @@ -898,14 +841,22 @@ openclaw googlemeet create } ``` -การสร้าง Meet จะเข้าร่วมตามค่าเริ่มต้น transport แบบ Chrome หรือ Chrome-node ยังต้องใช้โปรไฟล์ Google Chrome ที่ลงชื่อเข้าใช้เพื่อเข้าร่วมผ่านเบราว์เซอร์ หากโปรไฟล์ออกจากระบบอยู่ OpenClaw จะรายงาน `manualActionRequired: true` หรือข้อผิดพลาดทางเลือกสำรองของเบราว์เซอร์ และขอให้ผู้ปฏิบัติการทำการเข้าสู่ระบบ Google ให้เสร็จก่อนลองใหม่ +การสร้าง Meet จะเข้าร่วมโดยค่าเริ่มต้น ทรานสปอร์ต Chrome หรือ Chrome-node ยัง +ต้องใช้โปรไฟล์ Google Chrome ที่ลงชื่อเข้าใช้แล้วเพื่อเข้าร่วมผ่านเบราว์เซอร์ หาก +โปรไฟล์ออกจากระบบอยู่ OpenClaw จะรายงาน `manualActionRequired: true` หรือข้อผิดพลาด +การสำรองไปใช้เบราว์เซอร์ และขอให้ผู้ปฏิบัติงานล็อกอิน Google ให้เสร็จก่อนลองใหม่ -ตั้งค่า `preview.enrollmentAcknowledged: true` เฉพาะหลังจากยืนยันว่าโปรเจกต์ Cloud, principal ของ OAuth, และผู้เข้าร่วมการประชุมของคุณได้ลงทะเบียนใน Google Workspace Developer Preview Program สำหรับ Meet media APIs แล้ว +ตั้งค่า `preview.enrollmentAcknowledged: true` เฉพาะหลังจากยืนยันแล้วว่าโปรเจกต์ Cloud +ของคุณ, OAuth principal และผู้เข้าร่วมการประชุมได้ลงทะเบียนใน Google +Workspace Developer Preview Program สำหรับ Meet media APIs แล้ว ## การกำหนดค่า -เส้นทางเอเจนต์ Chrome ทั่วไปต้องการเพียงการเปิดใช้ Plugin, BlackHole, SoX, คีย์ผู้ให้บริการถอดเสียงแบบเรียลไทม์, และผู้ให้บริการ OpenClaw TTS ที่กำหนดค่าแล้ว -OpenAI เป็นผู้ให้บริการถอดเสียงตามค่าเริ่มต้น; ตั้งค่า `realtime.provider: "google"` เพื่อใช้ Google Gemini Live สำหรับโหมด `bidi`: +เส้นทางเอเจนต์ Chrome ทั่วไปต้องการเพียงเปิดใช้ Plugin, BlackHole, SoX, คีย์ +ผู้ให้บริการถอดเสียงแบบเรียลไทม์ และผู้ให้บริการ TTS ของ OpenClaw ที่กำหนดค่าไว้ +OpenAI เป็นผู้ให้บริการถอดเสียงเริ่มต้น; ตั้งค่า `realtime.voiceProvider` เป็น +`"google"` และ `realtime.model` เพื่อใช้ Google Gemini Live สำหรับโหมด `bidi` +โดยไม่เปลี่ยนผู้ให้บริการถอดเสียงเริ่มต้นของโหมดเอเจนต์: ```bash brew install blackhole-2ch sox @@ -932,45 +883,54 @@ export GEMINI_API_KEY=... ค่าเริ่มต้น: - `defaultTransport: "chrome"` -- `defaultMode: "agent"` (`"realtime"` ยอมรับเป็นนามแฝงเพื่อความเข้ากันได้สำหรับ - `"agent"`) -- `chromeNode.node`: รหัส/ชื่อ/IP ของ Node ที่ไม่บังคับสำหรับ `chrome-node` +- `defaultMode: "agent"` (`"realtime"` ยอมรับเฉพาะในฐานะนามแฝงความเข้ากันได้เดิม + สำหรับ `"agent"`; การเรียกเครื่องมือใหม่ควรระบุ `"agent"`) +- `chromeNode.node`: id/ชื่อ/IP ของ Node ที่ไม่บังคับสำหรับ `chrome-node` - `chrome.audioBackend: "blackhole-2ch"` -- `chrome.guestName: "OpenClaw Agent"`: ชื่อที่ใช้บนหน้าจอผู้เยี่ยมชม Meet ที่ยังไม่ได้ลงชื่อเข้าใช้ -- `chrome.autoJoin: true`: พยายามกรอกชื่อผู้เยี่ยมชมและคลิก Join Now ให้ดีที่สุด - ผ่านระบบอัตโนมัติของเบราว์เซอร์ OpenClaw บน `chrome-node` +- `chrome.guestName: "OpenClaw Agent"`: ชื่อที่ใช้บนหน้าจอแขก Meet ที่ยังไม่ได้ลงชื่อเข้าใช้ +- `chrome.autoJoin: true`: กรอกชื่อแขกและคลิก Join Now แบบพยายามดีที่สุด + ผ่านการทำงานอัตโนมัติของเบราว์เซอร์ OpenClaw บน `chrome-node` - `chrome.reuseExistingTab: true`: เปิดใช้งานแท็บ Meet ที่มีอยู่แทนการเปิดซ้ำ -- `chrome.waitForInCallMs: 20000`: รอให้แท็บ Meet รายงานว่าอยู่ในการโทร - ก่อนทริกเกอร์ข้อความแนะนำของเรียลไทม์ +- `chrome.waitForInCallMs: 20000`: รอให้แท็บ Meet รายงานว่าอยู่ในสาย + ก่อนทริกเกอร์บทนำแบบพูดตอบกลับ - `chrome.audioFormat: "pcm16-24khz"`: รูปแบบเสียงของคู่คำสั่ง ใช้ - `"g711-ulaw-8khz"` เฉพาะสำหรับคู่คำสั่งรุ่นเก่า/กำหนดเองที่ยังคงส่งเสียงโทรศัพท์ + `"g711-ulaw-8khz"` เฉพาะสำหรับคู่คำสั่งเดิม/กำหนดเองที่ยังส่งเสียงโทรศัพท์ออกมา +- `chrome.audioBufferBytes: 4096`: บัฟเฟอร์ประมวลผล SoX สำหรับคำสั่งเสียงคู่คำสั่ง + Chrome ที่สร้างขึ้น ค่านี้เป็นครึ่งหนึ่งของบัฟเฟอร์เริ่มต้น 8192 ไบต์ของ SoX + เพื่อลดเวลาแฝงของไปป์เริ่มต้นและยังเหลือพื้นที่ให้เพิ่มได้บนโฮสต์ที่มีงานหนาแน่น + ค่าที่ต่ำกว่าขั้นต่ำของ SoX จะถูกจำกัดไว้ที่ 17 ไบต์ - `chrome.audioInputCommand`: คำสั่ง SoX ที่อ่านจาก CoreAudio `BlackHole 2ch` และเขียนเสียงใน `chrome.audioFormat` - `chrome.audioOutputCommand`: คำสั่ง SoX ที่อ่านเสียงใน `chrome.audioFormat` และเขียนไปยัง CoreAudio `BlackHole 2ch` -- `chrome.bargeInInputCommand`: คำสั่งไมโครโฟนในเครื่องที่ไม่บังคับ ซึ่งเขียน PCM โมโน signed 16-bit little-endian สำหรับการตรวจจับการพูดแทรกของมนุษย์ขณะ +- `chrome.bargeInInputCommand`: คำสั่งไมโครโฟนภายในเครื่องที่ไม่บังคับ ซึ่งเขียน + PCM โมโน signed 16-bit little-endian สำหรับตรวจจับการพูดแทรกของมนุษย์ขณะ การเล่นเสียงของผู้ช่วยทำงานอยู่ ขณะนี้ใช้กับบริดจ์คู่คำสั่ง `chrome` ที่โฮสต์โดย Gateway -- `chrome.bargeInRmsThreshold: 650`: ระดับ RMS ที่นับเป็นการขัดจังหวะจากมนุษย์ +- `chrome.bargeInRmsThreshold: 650`: ระดับ RMS ที่นับเป็นการขัดจังหวะของมนุษย์ บน `chrome.bargeInInputCommand` -- `chrome.bargeInPeakThreshold: 2500`: ระดับพีคที่นับเป็นการขัดจังหวะจากมนุษย์ +- `chrome.bargeInPeakThreshold: 2500`: ระดับพีคที่นับเป็นการขัดจังหวะของมนุษย์ บน `chrome.bargeInInputCommand` -- `chrome.bargeInCooldownMs: 900`: หน่วงเวลาขั้นต่ำระหว่างการล้างสถานะการขัดจังหวะจากมนุษย์ซ้ำ -- `mode: "agent"`: โหมดตอบกลับเริ่มต้น คำพูดของผู้เข้าร่วมจะถูกถอดเสียงโดย - ผู้ให้บริการถอดเสียงเรียลไทม์ที่กำหนดค่าไว้ ส่งไปยัง - เอเจนต์ OpenClaw ที่กำหนดค่าไว้ในเซสชันเอเจนต์ย่อยต่อการประชุม และพูดตอบกลับผ่าน - รันไทม์ TTS ปกติของ OpenClaw -- `mode: "bidi"`: โหมดสำรองของโมเดลเรียลไทม์แบบสองทิศทางโดยตรง - ผู้ให้บริการเสียงเรียลไทม์จะตอบคำพูดของผู้เข้าร่วมโดยตรง และอาจเรียก - `openclaw_agent_consult` เพื่อคำตอบที่ลึกขึ้น/มีเครื่องมือสนับสนุน -- `mode: "transcribe"`: โหมดสังเกตการณ์อย่างเดียวโดยไม่มีบริดจ์ตอบกลับ -- `realtime.provider: "openai"`: รหัสผู้ให้บริการที่โหมด `agent` ใช้สำหรับ - การถอดเสียงเรียลไทม์ และโหมด `bidi` ใช้สำหรับเสียงเรียลไทม์ +- `chrome.bargeInCooldownMs: 900`: หน่วงเวลาขั้นต่ำระหว่างการล้างการขัดจังหวะของมนุษย์ซ้ำ +- `mode: "agent"`: โหมดพูดตอบกลับเริ่มต้น คำพูดของผู้เข้าร่วมจะถูกถอดเสียงโดย + ผู้ให้บริการถอดเสียงแบบเรียลไทม์ที่กำหนดค่าไว้ ส่งไปยังเอเจนต์ OpenClaw + ที่กำหนดค่าไว้ในเซสชันเอเจนต์ย่อยต่อการประชุม และพูดตอบกลับผ่าน runtime + TTS ปกติของ OpenClaw +- `mode: "bidi"`: โหมดสำรองโมเดลเรียลไทม์สองทิศทางโดยตรง ผู้ให้บริการเสียง + เรียลไทม์ตอบคำพูดของผู้เข้าร่วมโดยตรง และอาจเรียก + `openclaw_agent_consult` สำหรับคำตอบที่ลึกขึ้น/รองรับด้วยเครื่องมือ +- `mode: "transcribe"`: โหมดสังเกตการณ์เท่านั้นโดยไม่มีบริดจ์พูดตอบกลับ +- `realtime.provider: "openai"`: การสำรองความเข้ากันได้ที่ใช้เมื่อยังไม่ได้ตั้งค่า + ช่องผู้ให้บริการแบบ scoped ด้านล่าง +- `realtime.transcriptionProvider: "openai"`: id ผู้ให้บริการที่โหมด `agent` + ใช้สำหรับการถอดเสียงแบบเรียลไทม์ +- `realtime.voiceProvider`: id ผู้ให้บริการที่โหมด `bidi` ใช้สำหรับเสียงเรียลไทม์โดยตรง + ตั้งค่านี้เป็น `"google"` เพื่อใช้ Gemini Live โดยคงการถอดเสียงในโหมดเอเจนต์ไว้บน OpenAI - `realtime.toolPolicy: "safe-read-only"` - `realtime.instructions`: คำตอบพูดสั้น ๆ พร้อม `openclaw_agent_consult` สำหรับคำตอบที่ลึกขึ้น -- `realtime.introMessage`: การตรวจสอบความพร้อมแบบพูดสั้น ๆ เมื่อบริดจ์เรียลไทม์ - เชื่อมต่อ ตั้งเป็น `""` เพื่อเข้าร่วมแบบเงียบ -- `realtime.agentId`: รหัสเอเจนต์ OpenClaw ที่ไม่บังคับสำหรับ +- `realtime.introMessage`: การตรวจความพร้อมแบบพูดสั้น ๆ เมื่อบริดจ์เรียลไทม์ + เชื่อมต่อ; ตั้งเป็น `""` เพื่อเข้าร่วมแบบเงียบ +- `realtime.agentId`: id เอเจนต์ OpenClaw ที่ไม่บังคับสำหรับ `openclaw_agent_consult`; ค่าเริ่มต้นคือ `main` การแทนที่ที่ไม่บังคับ: @@ -1010,13 +970,15 @@ export GEMINI_API_KEY=... }, defaultMode: "agent", realtime: { - provider: "google", + provider: "openai", + transcriptionProvider: "openai", + voiceProvider: "google", + model: "gemini-2.5-flash-native-audio-preview-12-2025", agentId: "jay", toolPolicy: "owner", introMessage: "Say exactly: I'm here.", providers: { google: { - model: "gemini-2.5-flash-native-audio-preview-12-2025", voice: "Kore", }, }, @@ -1024,7 +986,51 @@ export GEMINI_API_KEY=... } ``` -การกำหนดค่าสำหรับ Twilio เท่านั้น: +ElevenLabs สำหรับทั้งการฟังและการพูดในโหมดเอเจนต์: + +```json5 +{ + messages: { + tts: { + provider: "elevenlabs", + providers: { + elevenlabs: { + modelId: "eleven_v3", + voiceId: "pMsXgVXv3BLzUgSXRplE", + }, + }, + }, + }, + plugins: { + entries: { + "google-meet": { + config: { + realtime: { + transcriptionProvider: "elevenlabs", + providers: { + elevenlabs: { + modelId: "scribe_v2_realtime", + audioFormat: "ulaw_8000", + sampleRate: 8000, + commitStrategy: "vad", + }, + }, + }, + }, + }, + }, + }, +} +``` + +เสียง Meet แบบคงอยู่มาจาก +`messages.tts.providers.elevenlabs.voiceId` คำตอบของเอเจนต์ยังสามารถใช้ +directive ต่อคำตอบ `[[tts:voiceId=... model=eleven_v3]]` ได้เมื่อเปิดใช้ +การแทนที่โมเดล TTS แต่การกำหนดค่าเป็นค่าเริ่มต้นแบบกำหนดได้แน่นอนสำหรับการประชุม +เมื่อเข้าร่วม log ควรแสดง `transcriptionProvider=elevenlabs` และคำตอบที่พูดแต่ละครั้ง +ควร log `provider=elevenlabs model=eleven_v3 voice=` + +การกำหนดค่าเฉพาะ Twilio: ```json5 { @@ -1039,11 +1045,11 @@ export GEMINI_API_KEY=... } ``` -ค่าเริ่มต้นของ `voiceCall.enabled` คือ `true`; เมื่อใช้การขนส่ง Twilio จะมอบหมาย -การโทร PSTN จริง, DTMF และคำทักทายเริ่มต้นให้กับ Plugin Voice Call โดย Voice Call -จะเล่นลำดับ DTMF ก่อนเปิดสตรีมสื่อเรียลไทม์ จากนั้นใช้ข้อความแนะนำที่บันทึกไว้ -เป็นคำทักทายเรียลไทม์เริ่มต้น หากไม่ได้เปิดใช้ `voice-call` -Google Meet ยังคงตรวจสอบและบันทึกแผนการโทรได้ แต่ไม่สามารถวางสาย Twilio ได้ +`voiceCall.enabled` มีค่าเริ่มต้นเป็น `true`; เมื่อใช้ทรานสปอร์ต Twilio จะมอบหมาย +การโทร PSTN จริง, DTMF และคำทักทายบทนำให้กับ Voice Call Plugin Voice Call +เล่นลำดับ DTMF ก่อนเปิดสตรีมสื่อเรียลไทม์ จากนั้นใช้ข้อความบทนำที่บันทึกไว้เป็น +คำทักทายเรียลไทม์เริ่มต้น หากไม่ได้เปิดใช้ `voice-call` Google Meet ยังสามารถ +ตรวจสอบและบันทึกแผนการโทรได้ แต่ไม่สามารถวางสายโทร Twilio ได้ ## เครื่องมือ @@ -1059,40 +1065,43 @@ Google Meet ยังคงตรวจสอบและบันทึกแ ``` ใช้ `transport: "chrome"` เมื่อ Chrome ทำงานบนโฮสต์ Gateway ใช้ -`transport: "chrome-node"` เมื่อ Chrome ทำงานบน Node ที่จับคู่ เช่น VM Parallels +`transport: "chrome-node"` เมื่อ Chrome ทำงานบน Node ที่จับคู่ไว้ เช่น VM Parallels ในทั้งสองกรณี ผู้ให้บริการโมเดลและ `openclaw_agent_consult` จะทำงานบนโฮสต์ -Gateway ดังนั้นข้อมูลประจำตัวของโมเดลจึงอยู่ที่นั่น ด้วยค่าเริ่มต้น `mode: "agent"` -ผู้ให้บริการถอดเสียงเรียลไทม์จะจัดการการฟัง เอเจนต์ OpenClaw ที่กำหนดค่าไว้จะสร้างคำตอบ -และ TTS ปกติของ OpenClaw จะพูดคำนั้นเข้า Meet ใช้ `mode: "bidi"` เมื่อคุณต้องการให้ -โมเดลเสียงเรียลไทม์ตอบโดยตรง `mode: "realtime"` ยังคงยอมรับเป็นนามแฝงเพื่อความเข้ากันได้สำหรับ -`mode: "agent"` +Gateway ดังนั้นข้อมูลรับรองโมเดลจึงอยู่ที่นั่น เมื่อใช้ค่าเริ่มต้น `mode: "agent"` +ผู้ให้บริการถอดเสียงแบบเรียลไทม์จัดการการฟัง เอเจนต์ OpenClaw ที่กำหนดค่าไว้ +สร้างคำตอบ และ TTS ปกติของ OpenClaw พูดเข้าไปใน Meet ใช้ `mode: "bidi"` +เมื่อคุณต้องการให้โมเดลเสียงเรียลไทม์ตอบโดยตรง +`mode: "realtime"` แบบดิบยังคงยอมรับในฐานะนามแฝงความเข้ากันได้เดิมสำหรับ +`mode: "agent"` แต่จะไม่ถูกโฆษณาใน schema เครื่องมือของเอเจนต์อีกต่อไป +log โหมดเอเจนต์มีผู้ให้บริการ/โมเดลถอดเสียงที่ resolve แล้วเมื่อบริดจ์เริ่มทำงาน +และผู้ให้บริการ TTS, โมเดล, เสียง, รูปแบบเอาต์พุต และอัตราสุ่มตัวอย่างหลังจาก +สังเคราะห์คำตอบแต่ละครั้ง -ใช้ `action: "status"` เพื่อแสดงรายการเซสชันที่ใช้งานอยู่หรือตรวจสอบรหัสเซสชัน ใช้ +ใช้ `action: "status"` เพื่อแสดงเซสชันที่ใช้งานอยู่หรือตรวจสอบ session ID ใช้ `action: "speak"` พร้อม `sessionId` และ `message` เพื่อให้เอเจนต์เรียลไทม์ -พูดทันที ใช้ `action: "test_speech"` เพื่อสร้างหรือใช้เซสชันซ้ำ -ทริกเกอร์วลีที่รู้จัก และส่งคืนสุขภาพ `inCall` เมื่อโฮสต์ Chrome สามารถ -รายงานได้ `test_speech` จะบังคับใช้ `mode: "agent"` เสมอ และจะล้มเหลวหากถูกขอให้ -ทำงานใน `mode: "transcribe"` เพราะเซสชันแบบสังเกตการณ์อย่างเดียวตั้งใจให้ -ไม่สามารถส่งเสียงพูดได้ ผลลัพธ์ `speechOutputVerified` อิงจากจำนวนไบต์เอาต์พุตเสียงเรียลไทม์ -ที่เพิ่มขึ้นระหว่างการทดสอบครั้งนี้ ดังนั้นเซสชันที่ใช้ซ้ำซึ่งมีเสียงเก่ากว่า -จะไม่นับเป็นการตรวจสอบเสียงพูดใหม่ที่สำเร็จ ใช้ `action: "leave"` เพื่อทำเครื่องหมายว่า -เซสชันสิ้นสุดแล้ว +พูดทันที ใช้ `action: "test_speech"` เพื่อสร้างหรือใช้เซสชันซ้ำ ทริกเกอร์วลีที่รู้จัก +และส่งคืนสุขภาพ `inCall` เมื่อโฮสต์ Chrome รายงานได้ `test_speech` บังคับใช้ +`mode: "agent"` เสมอ และล้มเหลวหากถูกขอให้รันใน `mode: "transcribe"` เพราะ +เซสชันสังเกตการณ์เท่านั้นตั้งใจไม่ให้ส่งเสียงออกได้ ผลลัพธ์ `speechOutputVerified` +อิงกับจำนวนไบต์เอาต์พุตเสียงเรียลไทม์ที่เพิ่มขึ้นระหว่างการเรียกทดสอบนี้ ดังนั้น +เซสชันที่ใช้ซ้ำซึ่งมีเสียงเก่าจะไม่นับเป็นการตรวจคำพูดที่สำเร็จใหม่ ใช้ +`action: "leave"` เพื่อทำเครื่องหมายว่าเซสชันสิ้นสุดแล้ว -`status` รวมสุขภาพของ Chrome เมื่อมีข้อมูล: +`status` มีสุขภาพ Chrome เมื่อพร้อมใช้งาน: - `inCall`: Chrome ดูเหมือนอยู่ภายในสาย Meet -- `micMuted`: สถานะไมโครโฟน Meet แบบพยายามให้ดีที่สุด +- `micMuted`: สถานะไมโครโฟน Meet แบบพยายามดีที่สุด - `manualActionRequired` / `manualActionReason` / `manualActionMessage`: โปรไฟล์ - เบราว์เซอร์ต้องการการเข้าสู่ระบบด้วยตนเอง การอนุญาตจากโฮสต์ Meet สิทธิ์อนุญาต หรือ - การซ่อมการควบคุมเบราว์เซอร์ก่อนที่เสียงพูดจะทำงานได้ -- `speechReady` / `speechBlockedReason` / `speechBlockedMessage`: ระบุว่า - อนุญาตให้ใช้เสียงพูดของ Chrome ที่จัดการอยู่ในตอนนี้หรือไม่ `speechReady: false` หมายความว่า OpenClaw - ไม่ได้ส่งวลีแนะนำ/ทดสอบเข้าไปในบริดจ์เสียง + เบราว์เซอร์ต้องการการล็อกอินด้วยมือ การอนุญาตเข้าโดยโฮสต์ Meet สิทธิ์ หรือ + การซ่อมแซมการควบคุมเบราว์เซอร์ก่อนที่เสียงพูดจะทำงานได้ +- `speechReady` / `speechBlockedReason` / `speechBlockedMessage`: ว่าเสียงพูด + Chrome ที่จัดการอยู่ได้รับอนุญาตตอนนี้หรือไม่ `speechReady: false` หมายความว่า + OpenClaw ไม่ได้ส่งวลีบทนำ/ทดสอบเข้าไปในบริดจ์เสียง - `providerConnected` / `realtimeReady`: สถานะบริดจ์เสียงเรียลไทม์ -- `lastInputAt` / `lastOutputAt`: เสียงล่าสุดที่เห็นจากบริดจ์หรือส่งไปยังบริดจ์ -- `audioOutputRouted` / `audioOutputDeviceLabel`: ระบุว่าเอาต์พุตสื่อของแท็บ Meet - ถูกกำหนดเส้นทางอย่างใช้งานไปยังอุปกรณ์ BlackHole ที่บริดจ์ใช้หรือไม่ -- `lastSuppressedInputAt` / `suppressedInputBytes`: อินพุต loopback ที่ถูกละเว้นขณะ +- `lastInputAt` / `lastOutputAt`: เสียงล่าสุดที่เห็นจากหรือส่งไปยังบริดจ์ +- `audioOutputRouted` / `audioOutputDeviceLabel`: ว่าเอาต์พุตสื่อของแท็บ Meet + ถูก route ไปยังอุปกรณ์ BlackHole ที่บริดจ์ใช้โดยตรงหรือไม่ +- `lastSuppressedInputAt` / `suppressedInputBytes`: อินพุต local loopback ที่ถูกละเว้นขณะ การเล่นเสียงของผู้ช่วยทำงานอยู่ ```json @@ -1103,59 +1112,47 @@ Gateway ดังนั้นข้อมูลประจำตัวของ } ``` -## โหมดเอเจนต์และสองทิศทาง +## โหมด Agent และ Bidi -โหมด `agent` ของ Chrome ถูกปรับให้เหมาะกับพฤติกรรม "เอเจนต์ของฉันอยู่ในการประชุม" -ผู้ให้บริการถอดเสียงเรียลไทม์ได้ยินเสียงการประชุม ทรานสคริปต์สุดท้ายของผู้เข้าร่วม -ถูกส่งผ่านเอเจนต์ OpenClaw ที่กำหนดค่าไว้ และคำตอบถูกพูดผ่านรันไทม์ TTS ปกติของ OpenClaw -ตั้งค่า `mode: "bidi"` เมื่อคุณต้องการให้โมเดลเสียงเรียลไทม์ตอบโดยตรง -เศษทรานสคริปต์สุดท้ายที่อยู่ใกล้กันจะถูกรวมเข้าด้วยกันก่อนการ consult เพื่อให้การพูดหนึ่งรอบ -ไม่สร้างคำตอบบางส่วนเก่าหลายรายการ อินพุตเรียลไทม์จะถูกระงับด้วย -ขณะที่เสียงผู้ช่วยที่จัดคิวยังเล่นอยู่ -และเสียงสะท้อนทรานสคริปต์ที่คล้ายผู้ช่วยเมื่อเร็ว ๆ นี้จะถูกละเว้นก่อนการ consult ของเอเจนต์ -เพื่อไม่ให้ loopback ของ BlackHole ทำให้เอเจนต์ตอบคำพูดของตัวเอง +โหมด Chrome `agent` ปรับให้เหมาะกับพฤติกรรม "เอเจนต์ของฉันอยู่ในการประชุม" +ผู้ให้บริการถอดเสียงแบบเรียลไทม์ฟังเสียงการประชุม transcript สุดท้ายของผู้เข้าร่วม +จะถูกส่งผ่านเอเจนต์ OpenClaw ที่กำหนดค่าไว้ และคำตอบจะถูกพูดผ่าน runtime TTS +ปกติของ OpenClaw ตั้งค่า `mode: "bidi"` เมื่อคุณต้องการให้โมเดลเสียงเรียลไทม์ตอบโดยตรง +ชิ้นส่วน transcript สุดท้ายที่อยู่ใกล้กันจะถูกผสานก่อน consult เพื่อให้หนึ่งรอบการพูด +ไม่สร้างคำตอบ partial ที่ค้างอยู่หลายรายการ อินพุตเรียลไทม์ยังถูกระงับขณะเสียง +ผู้ช่วยที่อยู่ในคิวยังคงเล่นอยู่ +และเสียงสะท้อน transcript ที่คล้ายผู้ช่วยเมื่อเร็ว ๆ นี้จะถูกละเว้นก่อน consult +เอเจนต์ เพื่อให้ local loopback ของ BlackHole ไม่ทำให้เอเจนต์ตอบคำพูดของตัวเอง -| โหมด | ผู้ตัดสินคำตอบ | เส้นทางเอาต์พุตเสียงพูด | ใช้เมื่อ | +| โหมด | ใครตัดสินคำตอบ | เส้นทางเอาต์พุตเสียง | ใช้เมื่อ | | ------- | ----------------------------- | -------------------------------------- | ----------------------------------------------------- | -| `agent` | เอเจนต์ OpenClaw ที่กำหนดค่าไว้ | รันไทม์ TTS ปกติของ OpenClaw | คุณต้องการพฤติกรรม "เอเจนต์ของฉันอยู่ในการประชุม" | -| `bidi` | โมเดลเสียงเรียลไทม์ | การตอบกลับเสียงของผู้ให้บริการเสียงเรียลไทม์ | คุณต้องการลูปเสียงสนทนาที่มีความหน่วงต่ำที่สุด | +| `agent` | เอเจนต์ OpenClaw ที่กำหนดค่าไว้ | runtime TTS ปกติของ OpenClaw | คุณต้องการพฤติกรรม "เอเจนต์ของฉันอยู่ในการประชุม" | +| `bidi` | โมเดลเสียงเรียลไทม์ | การตอบกลับเสียงของผู้ให้บริการเสียงเรียลไทม์ | คุณต้องการลูปเสียงสนทนาที่มีเวลาแฝงต่ำที่สุด | -ในโหมด `bidi` เมื่อโมเดลเรียลไทม์ต้องการการให้เหตุผลที่ลึกขึ้น -ข้อมูลปัจจุบัน หรือเครื่องมือ OpenClaw ปกติ ก็สามารถเรียก `openclaw_agent_consult` ได้ +ในโหมด `bidi` เมื่อโมเดลเรียลไทม์ต้องการการให้เหตุผลที่ลึกขึ้น ข้อมูลปัจจุบัน +หรือเครื่องมือ OpenClaw ปกติ ก็สามารถเรียก `openclaw_agent_consult` ได้ -เครื่องมือ consult จะเรียกใช้เอเจนต์ OpenClaw ปกติอยู่เบื้องหลัง พร้อมบริบท -ทรานสคริปต์การประชุมล่าสุด และส่งคืนคำตอบพูดที่กระชับ ในโหมด `agent` -OpenClaw จะส่งคำตอบนั้นตรงไปยังรันไทม์ TTS; ในโหมด `bidi` -โมเดลเสียงเรียลไทม์สามารถพูดผลลัพธ์ consult กลับเข้าไปในการประชุมได้ โดยใช้ -กลไก consult ที่ใช้ร่วมกันเดียวกับ Voice Call +เครื่องมือ consult เรียกใช้เอเจนต์ OpenClaw ปกติอยู่เบื้องหลังพร้อมบริบทบันทึกการประชุมล่าสุด และส่งคำตอบแบบพูดที่กระชับกลับมา ในโหมด `agent` OpenClaw จะส่งคำตอบนั้นไปยังรันไทม์ TTS โดยตรง ส่วนในโหมด `bidi` โมเดลเสียงแบบเรียลไทม์สามารถพูดผลลัพธ์ consult กลับเข้าไปในการประชุมได้ โดยใช้กลไก consult ร่วมเดียวกับ Voice Call -โดยค่าเริ่มต้น consult จะทำงานกับเอเจนต์ `main` ตั้งค่า `realtime.agentId` เมื่อ -เลน Meet ควร consult เวิร์กสเปซเอเจนต์ OpenClaw เฉพาะ ค่าเริ่มต้นของโมเดล -นโยบายเครื่องมือ หน่วยความจำ และประวัติเซสชัน +ตามค่าเริ่มต้น consult จะทำงานกับเอเจนต์ `main` ตั้งค่า `realtime.agentId` เมื่อเลน Meet ควร consult เวิร์กสเปซเอเจนต์ OpenClaw เฉพาะ ค่าเริ่มต้นของโมเดล นโยบายเครื่องมือ หน่วยความจำ และประวัติเซสชันเฉพาะ -consult ในโหมดเอเจนต์ใช้คีย์เซสชัน `agent::subagent:google-meet:` -แบบต่อการประชุม เพื่อให้คำถามติดตามผลรักษาบริบทการประชุมไว้ขณะสืบทอดนโยบาย -เอเจนต์ปกติจากเอเจนต์ที่กำหนดค่าไว้ +consult ในโหมดเอเจนต์ใช้คีย์เซสชันต่อการประชุม `agent::subagent:google-meet:` เพื่อให้คำถามติดตามผลยังคงบริบทการประชุมไว้ พร้อมสืบทอดนโยบายเอเจนต์ปกติจากเอเจนต์ที่กำหนดค่าไว้ -`realtime.toolPolicy` ควบคุมการรัน consult: +`realtime.toolPolicy` ควบคุมการเรียกใช้งาน consult: -- `safe-read-only`: เปิดเผยเครื่องมือ consult และจำกัดเอเจนต์ปกติให้ใช้ - `read`, `web_search`, `web_fetch`, `x_search`, `memory_search` และ - `memory_get` -- `owner`: เปิดเผยเครื่องมือ consult และให้เอเจนต์ปกติใช้นโยบายเครื่องมือ - เอเจนต์ปกติ -- `none`: ไม่เปิดเผยเครื่องมือ consult ให้โมเดลเสียงเรียลไทม์ +- `safe-read-only`: เปิดเผยเครื่องมือ consult และจำกัดเอเจนต์ปกติให้ใช้ `read`, `web_search`, `web_fetch`, `x_search`, `memory_search` และ `memory_get` +- `owner`: เปิดเผยเครื่องมือ consult และให้เอเจนต์ปกติใช้นโยบายเครื่องมือเอเจนต์ปกติ +- `none`: ไม่เปิดเผยเครื่องมือ consult ให้โมเดลเสียงแบบเรียลไทม์ -คีย์เซสชัน consult ถูกกำหนดขอบเขตต่อเซสชัน Meet ดังนั้นการเรียก consult ติดตามผล -จึงสามารถใช้บริบท consult ก่อนหน้าในระหว่างการประชุมเดียวกันได้ +คีย์เซสชัน consult ถูกจำกัดขอบเขตต่อเซสชัน Meet ดังนั้นการเรียก consult ติดตามผลจึงสามารถนำบริบท consult ก่อนหน้ามาใช้ซ้ำระหว่างการประชุมเดียวกันได้ -เพื่อบังคับการตรวจสอบความพร้อมแบบพูดหลังจาก Chrome เข้าร่วมสายเรียบร้อยแล้ว: +หากต้องการบังคับการตรวจสอบความพร้อมแบบพูดหลังจาก Chrome เข้าร่วมสายเรียบร้อยแล้ว: ```bash openclaw googlemeet speak meet_... "Say exactly: I'm here and listening." ``` -สำหรับ smoke การเข้าร่วมและพูดแบบเต็ม: +สำหรับการทดสอบ smoke แบบเข้าร่วมและพูดครบถ้วน: ```bash openclaw googlemeet test-speech https://meet.google.com/abc-defg-hij \ @@ -1175,18 +1172,15 @@ openclaw googlemeet test-speech https://meet.google.com/abc-defg-hij \ --message "Say exactly: Google Meet speech test complete." ``` -สถานะ Chrome-node ที่คาดหวัง: +สถานะ Chrome-node ที่คาดไว้: - `googlemeet setup` เป็นสีเขียวทั้งหมด -- `googlemeet setup` รวม `chrome-node-connected` เมื่อ Chrome-node เป็น - การขนส่งเริ่มต้นหรือมีการปักหมุด Node +- `googlemeet setup` รวม `chrome-node-connected` เมื่อ Chrome-node เป็นทรานสปอร์ตเริ่มต้นหรือมีการตรึง Node ไว้ - `nodes status` แสดงว่า Node ที่เลือกเชื่อมต่ออยู่ - Node ที่เลือกประกาศทั้ง `googlemeet.chrome` และ `browser.proxy` -- แท็บ Meet เข้าร่วมสาย และ `test-speech` ส่งคืนสุขภาพ Chrome พร้อม - `inCall: true` +- แท็บ Meet เข้าร่วมสาย และ `test-speech` ส่งคืนสุขภาพ Chrome พร้อม `inCall: true` -สำหรับโฮสต์ Chrome ระยะไกล เช่น VM Parallels macOS นี่คือการตรวจสอบที่สั้นที่สุด -และปลอดภัยหลังอัปเดต Gateway หรือ VM: +สำหรับโฮสต์ Chrome ระยะไกล เช่น VM macOS ของ Parallels นี่คือการตรวจสอบที่ปลอดภัยและสั้นที่สุดหลังอัปเดต Gateway หรือ VM: ```bash openclaw googlemeet setup @@ -1197,11 +1191,9 @@ openclaw nodes invoke \ --params '{"action":"setup"}' ``` -สิ่งนี้พิสูจน์ว่า Plugin Gateway ถูกโหลดแล้ว, Node VM เชื่อมต่อด้วย -โทเค็นปัจจุบัน และบริดจ์เสียง Meet พร้อมใช้งานก่อนที่เอเจนต์จะเปิด -แท็บการประชุมจริง +สิ่งนี้พิสูจน์ว่า Plugin ของ Gateway ถูกโหลดแล้ว, Node ของ VM เชื่อมต่อด้วยโทเค็นปัจจุบัน และสะพานเสียง Meet พร้อมใช้งานก่อนที่เอเจนต์จะเปิดแท็บการประชุมจริง -สำหรับ smoke ของ Twilio ให้ใช้การประชุมที่แสดงรายละเอียดการโทรเข้าทางโทรศัพท์: +สำหรับการทดสอบ smoke ของ Twilio ให้ใช้การประชุมที่เปิดเผยรายละเอียดการโทรเข้า: ```bash openclaw googlemeet setup @@ -1211,38 +1203,30 @@ openclaw googlemeet join https://meet.google.com/abc-defg-hij \ --pin 123456 ``` -สถานะ Twilio ที่คาดหวัง: +สถานะ Twilio ที่คาดไว้: -- `googlemeet setup` มีการตรวจสอบ `twilio-voice-call-plugin`, - `twilio-voice-call-credentials` และ `twilio-voice-call-webhook` เป็นสีเขียว -- `voicecall` พร้อมใช้งานใน CLI หลังจากโหลด Gateway ใหม่ +- `googlemeet setup` รวมการตรวจสอบ `twilio-voice-call-plugin`, `twilio-voice-call-credentials` และ `twilio-voice-call-webhook` ที่เป็นสีเขียว +- `voicecall` พร้อมใช้งานใน CLI หลังโหลด Gateway ใหม่ - เซสชันที่ส่งคืนมี `transport: "twilio"` และ `twilio.voiceCallId` -- `openclaw logs --follow` แสดง DTMF TwiML ที่ถูกให้บริการก่อน realtime TwiML จากนั้นเป็น - บริดจ์ realtime พร้อมคำทักทายเริ่มต้นที่เข้าคิวไว้ -- `googlemeet leave ` วางสายการโทรเสียงที่มอบหมายไว้ +- `openclaw logs --follow` แสดงว่า DTMF TwiML ถูกให้บริการก่อน TwiML แบบเรียลไทม์ จากนั้นเป็นสะพานเรียลไทม์พร้อมคำทักทายเริ่มต้นที่ถูกเข้าคิวไว้ +- `googlemeet leave ` วางสายการโทรด้วยเสียงที่มอบหมายแล้ว ## การแก้ไขปัญหา ### เอเจนต์มองไม่เห็นเครื่องมือ Google Meet -ยืนยันว่า Plugin ถูกเปิดใช้งานในการกำหนดค่า Gateway และโหลด Gateway ใหม่: +ยืนยันว่า Plugin เปิดใช้งานอยู่ในการกำหนดค่า Gateway และโหลด Gateway ใหม่: ```bash openclaw plugins list | grep google-meet openclaw googlemeet setup ``` -หากคุณเพิ่งแก้ไข `plugins.entries.google-meet` ให้รีสตาร์ตหรือโหลด Gateway ใหม่ -เอเจนต์ที่กำลังทำงานจะเห็นเฉพาะเครื่องมือ Plugin ที่ลงทะเบียนโดยกระบวนการ Gateway -ปัจจุบันเท่านั้น +หากคุณเพิ่งแก้ไข `plugins.entries.google-meet` ให้รีสตาร์ตหรือโหลด Gateway ใหม่ เอเจนต์ที่กำลังทำงานจะเห็นเฉพาะเครื่องมือ Plugin ที่ลงทะเบียนโดยกระบวนการ Gateway ปัจจุบันเท่านั้น -บนโฮสต์ Gateway ที่ไม่ใช่ macOS เครื่องมือ `google_meet` สำหรับเอเจนต์จะยังมองเห็นได้ -แต่การทำงาน Chrome talk-back ในเครื่องจะถูกบล็อกก่อนถึงบริดจ์เสียง -เสียง Chrome talk-back ในเครื่องขณะนี้ขึ้นกับ `BlackHole 2ch` ของ macOS ดังนั้น -เอเจนต์ Linux ควรใช้ `mode: "transcribe"` การโทรเข้า Twilio หรือโฮสต์ -`chrome-node` ของ macOS แทนเส้นทางเอเจนต์ Chrome ในเครื่องเริ่มต้น +บนโฮสต์ Gateway ที่ไม่ใช่ macOS เครื่องมือ `google_meet` สำหรับเอเจนต์ยังคงมองเห็นได้ แต่การกระทำพูดกลับของ Chrome ในเครื่องจะถูกบล็อกก่อนถึงสะพานเสียง เสียงพูดกลับของ Chrome ในเครื่องในปัจจุบันขึ้นกับ `BlackHole 2ch` บน macOS ดังนั้นเอเจนต์ Linux ควรใช้ `mode: "transcribe"`, การโทรเข้า Twilio หรือโฮสต์ `chrome-node` บน macOS แทนเส้นทางเอเจนต์ Chrome ในเครื่องตามค่าเริ่มต้น -### ไม่มี Node ที่รองรับ Google Meet เชื่อมต่ออยู่ +### ไม่มี Node ที่เชื่อมต่อและรองรับ Google Meet บนโฮสต์ Node ให้รัน: @@ -1261,8 +1245,7 @@ openclaw devices approve openclaw nodes status ``` -Node ต้องเชื่อมต่ออยู่และแสดงรายการ `googlemeet.chrome` พร้อมกับ `browser.proxy` -การกำหนดค่า Gateway ต้องอนุญาตคำสั่ง Node เหล่านั้น: +Node ต้องเชื่อมต่ออยู่และแสดง `googlemeet.chrome` พร้อม `browser.proxy` การกำหนดค่า Gateway ต้องอนุญาตคำสั่ง Node เหล่านั้น: ```json5 { @@ -1274,9 +1257,7 @@ Node ต้องเชื่อมต่ออยู่และแสดงร } ``` -หาก `googlemeet setup` ล้มเหลวที่ `chrome-node-connected` หรือบันทึก Gateway รายงาน -`gateway token mismatch` ให้ติดตั้งใหม่หรือรีสตาร์ต Node ด้วยโทเค็น Gateway ปัจจุบัน -สำหรับ Gateway บน LAN โดยปกติหมายถึง: +หาก `googlemeet setup` ล้มเหลวที่ `chrome-node-connected` หรือบันทึก Gateway รายงาน `gateway token mismatch` ให้ติดตั้งใหม่หรือรีสตาร์ต Node ด้วยโทเค็น Gateway ปัจจุบัน สำหรับ Gateway บน LAN โดยทั่วไปหมายถึง: ```bash OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1 \ @@ -1294,121 +1275,67 @@ openclaw googlemeet setup openclaw nodes status --connected ``` -### เบราว์เซอร์เปิดขึ้นแต่เอเจนต์เข้าร่วมไม่ได้ +### เบราว์เซอร์เปิดได้แต่เอเจนต์เข้าร่วมไม่ได้ -รัน `googlemeet test-listen` สำหรับการเข้าร่วมแบบสังเกตการณ์เท่านั้น หรือ `googlemeet test-speech` -สำหรับการเข้าร่วมแบบ realtime แล้วตรวจสอบสถานะสุขภาพ Chrome ที่ส่งคืน หากโพรบใดรายงาน -`manualActionRequired: true` ให้แสดง `manualActionMessage` ต่อผู้ปฏิบัติงาน -และหยุดลองซ้ำจนกว่าการทำงานในเบราว์เซอร์จะเสร็จสมบูรณ์ +รัน `googlemeet test-listen` สำหรับการเข้าร่วมแบบสังเกตเท่านั้น หรือ `googlemeet test-speech` สำหรับการเข้าร่วมแบบเรียลไทม์ จากนั้นตรวจสอบสุขภาพ Chrome ที่ส่งคืน หากโพรบใดรายงาน `manualActionRequired: true` ให้แสดง `manualActionMessage` แก่ผู้ปฏิบัติงานและหยุดลองซ้ำจนกว่าการกระทำในเบราว์เซอร์จะเสร็จสมบูรณ์ -การทำงานด้วยตนเองที่พบบ่อย: +การกระทำด้วยตนเองที่พบบ่อย: - ลงชื่อเข้าใช้โปรไฟล์ Chrome -- อนุญาตผู้เข้าร่วมจากบัญชีโฮสต์ Meet -- ให้สิทธิ์ไมโครโฟน/กล้องแก่ Chrome เมื่อพรอมป์สิทธิ์แบบเนทีฟของ Chrome ปรากฏ -- ปิดหรือซ่อมกล่องโต้ตอบสิทธิ์ Meet ที่ค้างอยู่ +- รับผู้เข้าร่วมแบบแขกจากบัญชีโฮสต์ Meet +- ให้สิทธิ์ไมโครโฟน/กล้องแก่ Chrome เมื่อพร้อมต์สิทธิ์แบบเนทีฟของ Chrome ปรากฏ +- ปิดหรือซ่อมแซมกล่องโต้ตอบสิทธิ์ Meet ที่ค้างอยู่ -อย่ารายงานว่า "not signed in" เพียงเพราะ Meet แสดง "Do you want people to -hear you in the meeting?" นั่นคือหน้าคั่นการเลือกเสียงของ Meet; OpenClaw -คลิก **Use microphone** ผ่านการทำงานอัตโนมัติของเบราว์เซอร์เมื่อพร้อมใช้งาน และยังคง -รอสถานะการประชุมจริงต่อไป สำหรับ browser fallback แบบสร้างอย่างเดียว OpenClaw -อาจคลิก **Continue without microphone** เพราะการสร้าง URL ไม่ต้องใช้ -เส้นทางเสียง realtime +อย่ารายงานว่า "not signed in" เพียงเพราะ Meet แสดง "Do you want people to hear you in the meeting?" นั่นคือหน้าคั่นเลือกเสียงของ Meet; OpenClaw คลิก **Use microphone** ผ่านระบบอัตโนมัติของเบราว์เซอร์เมื่อพร้อมใช้งาน และรอต่อไปจนถึงสถานะการประชุมจริง สำหรับทางเลือกเบราว์เซอร์แบบสร้างอย่างเดียว OpenClaw อาจคลิก **Continue without microphone** เพราะการสร้าง URL ไม่ต้องใช้เส้นทางเสียงแบบเรียลไทม์ -### การสร้างการประชุมล้มเหลว +### สร้างการประชุมล้มเหลว -`googlemeet create` ใช้เอนด์พอยต์ Google Meet API `spaces.create` ก่อน -เมื่อมีการกำหนดค่าข้อมูลรับรอง OAuth หากไม่มีข้อมูลรับรอง OAuth จะ fallback -ไปยังเบราว์เซอร์ Chrome Node ที่ปักหมุดไว้ ยืนยันว่า: +`googlemeet create` ใช้เอนด์พอยต์ `spaces.create` ของ Google Meet API ก่อนเมื่อกำหนดค่าข้อมูลรับรอง OAuth ไว้ หากไม่มีข้อมูลรับรอง OAuth จะถอยกลับไปใช้เบราว์เซอร์ของ Node Chrome ที่ตรึงไว้ ยืนยันว่า: -- สำหรับการสร้างผ่าน API: มีการกำหนดค่า `oauth.clientId` และ `oauth.refreshToken` - หรือมีตัวแปรสภาพแวดล้อม `OPENCLAW_GOOGLE_MEET_*` ที่ตรงกัน -- สำหรับการสร้างผ่าน API: โทเค็นรีเฟรชถูกออกหลังจากเพิ่มการรองรับการสร้างแล้ว - โทเค็นรุ่นเก่าอาจไม่มี scope `meetings.space.created`; ให้รัน - `openclaw googlemeet auth login --json` อีกครั้งและอัปเดตการกำหนดค่า Plugin -- สำหรับ browser fallback: `defaultTransport: "chrome-node"` และ - `chromeNode.node` ชี้ไปยัง Node ที่เชื่อมต่ออยู่พร้อม `browser.proxy` และ - `googlemeet.chrome` -- สำหรับ browser fallback: โปรไฟล์ Chrome ของ OpenClaw บน Node นั้นลงชื่อเข้าใช้ - Google แล้วและสามารถเปิด `https://meet.google.com/new` -- สำหรับ browser fallback: การลองซ้ำใช้แท็บ `https://meet.google.com/new` - หรือแท็บพรอมป์บัญชี Google ที่มีอยู่ก่อนเปิดแท็บใหม่ หากเอเจนต์หมดเวลา - ให้ลองเรียกเครื่องมือซ้ำแทนการเปิดแท็บ Meet อีกแท็บด้วยตนเอง -- สำหรับ browser fallback: หากเครื่องมือส่งคืน `manualActionRequired: true` ให้ใช้ - `browser.nodeId`, `browser.targetId`, `browserUrl` และ - `manualActionMessage` ที่ส่งคืนมาเพื่อแนะนำผู้ปฏิบัติงาน อย่าลองซ้ำวนไปมาจนกว่า - การทำงานนั้นจะเสร็จสมบูรณ์ -- สำหรับ browser fallback: หาก Meet แสดง "Do you want people to hear you in the - meeting?" ให้เปิดแท็บทิ้งไว้ OpenClaw ควรคลิก **Use microphone** หรือสำหรับ - fallback แบบสร้างอย่างเดียว คลิก **Continue without microphone** ผ่านการทำงานอัตโนมัติ - ของเบราว์เซอร์และรอ URL Meet ที่สร้างต่อไป หากทำไม่ได้ ข้อผิดพลาดควรกล่าวถึง - `meet-audio-choice-required` ไม่ใช่ `google-login-required` +- สำหรับการสร้างผ่าน API: กำหนดค่า `oauth.clientId` และ `oauth.refreshToken` แล้ว หรือมีตัวแปรสภาพแวดล้อม `OPENCLAW_GOOGLE_MEET_*` ที่ตรงกัน +- สำหรับการสร้างผ่าน API: โทเค็นรีเฟรชถูกสร้างหลังจากเพิ่มการรองรับการสร้างแล้ว โทเค็นเก่าอาจไม่มีขอบเขต `meetings.space.created`; รัน `openclaw googlemeet auth login --json` อีกครั้งและอัปเดตการกำหนดค่า Plugin +- สำหรับทางเลือกเบราว์เซอร์: `defaultTransport: "chrome-node"` และ `chromeNode.node` ชี้ไปยัง Node ที่เชื่อมต่ออยู่พร้อม `browser.proxy` และ `googlemeet.chrome` +- สำหรับทางเลือกเบราว์เซอร์: โปรไฟล์ Chrome ของ OpenClaw บน Node นั้นลงชื่อเข้าใช้ Google แล้วและเปิด `https://meet.google.com/new` ได้ +- สำหรับทางเลือกเบราว์เซอร์: การลองซ้ำจะนำแท็บ `https://meet.google.com/new` หรือแท็บพร้อมต์บัญชี Google ที่มีอยู่มาใช้ซ้ำก่อนเปิดแท็บใหม่ หากเอเจนต์หมดเวลา ให้ลองเรียกเครื่องมือซ้ำแทนการเปิดแท็บ Meet อีกแท็บด้วยตนเอง +- สำหรับทางเลือกเบราว์เซอร์: หากเครื่องมือส่งคืน `manualActionRequired: true` ให้ใช้ `browser.nodeId`, `browser.targetId`, `browserUrl` และ `manualActionMessage` ที่ส่งคืนเพื่อแนะนำผู้ปฏิบัติงาน อย่าลองซ้ำวนไปจนกว่าการกระทำนั้นจะเสร็จสมบูรณ์ +- สำหรับทางเลือกเบราว์เซอร์: หาก Meet แสดง "Do you want people to hear you in the meeting?" ให้ปล่อยแท็บไว้ OpenClaw ควรคลิก **Use microphone** หรือสำหรับทางเลือกแบบสร้างอย่างเดียว คลิก **Continue without microphone** ผ่านระบบอัตโนมัติของเบราว์เซอร์และรอต่อไปจนได้ URL Meet ที่สร้างขึ้น หากทำไม่ได้ ข้อผิดพลาดควรกล่าวถึง `meet-audio-choice-required` ไม่ใช่ `google-login-required` ### เอเจนต์เข้าร่วมแล้วแต่ไม่พูด -ตรวจสอบเส้นทาง realtime: +ตรวจสอบเส้นทางเรียลไทม์: ```bash openclaw googlemeet setup openclaw googlemeet doctor ``` -ใช้ `mode: "agent"` สำหรับเส้นทาง talk-back ปกติ STT -> เอเจนต์ OpenClaw -> TTS -หรือ `mode: "bidi"` สำหรับ fallback เสียง realtime โดยตรง `mode: "transcribe"` -ตั้งใจไม่เริ่มบริดจ์ talk-back สำหรับการดีบักแบบสังเกตการณ์เท่านั้น -ให้รัน `openclaw googlemeet status --json ` หลังจากผู้เข้าร่วมพูด -และตรวจสอบ `captioning`, `transcriptLines` และ `lastCaptionText` หาก `inCall` เป็น -true แต่ `transcriptLines` ยังคงเป็น `0` อาจเป็นเพราะคำบรรยาย Meet ถูกปิดใช้งาน -ยังไม่มีใครพูดตั้งแต่ติดตั้งตัวสังเกตการณ์ UI ของ Meet เปลี่ยนไป หรือ live -captions ไม่พร้อมใช้งานสำหรับภาษา/บัญชีของการประชุม +ใช้ `mode: "agent"` สำหรับเส้นทางพูดกลับปกติ STT -> เอเจนต์ OpenClaw -> TTS หรือ `mode: "bidi"` สำหรับทางเลือกเสียงเรียลไทม์โดยตรง `mode: "transcribe"` ตั้งใจไม่เริ่มสะพานพูดกลับ สำหรับการดีบักแบบสังเกตเท่านั้น ให้รัน `openclaw googlemeet status --json ` หลังผู้เข้าร่วมพูด และตรวจสอบ `captioning`, `transcriptLines` และ `lastCaptionText` หาก `inCall` เป็น true แต่ `transcriptLines` ค้างที่ `0` แคปชัน Meet อาจถูกปิดใช้งาน ยังไม่มีใครพูดตั้งแต่ติดตั้งตัวสังเกตการณ์ UI ของ Meet เปลี่ยนไป หรือแคปชันสดไม่พร้อมใช้งานสำหรับภาษา/บัญชีของการประชุม -`googlemeet test-speech` ตรวจสอบเส้นทาง realtime เสมอและรายงานว่า -พบไบต์เอาต์พุตบริดจ์สำหรับการเรียกใช้นั้นหรือไม่ หาก `speechOutputVerified` เป็น false และ -`speechOutputTimedOut` เป็น true ผู้ให้บริการ realtime อาจยอมรับถ้อยคำแล้ว -แต่ OpenClaw ไม่เห็นไบต์เอาต์พุตใหม่ไปถึงบริดจ์เสียง Chrome +`googlemeet test-speech` ตรวจสอบเส้นทางเรียลไทม์เสมอ และรายงานว่ามีการสังเกตไบต์เอาต์พุตของสะพานสำหรับการเรียกใช้นั้นหรือไม่ หาก `speechOutputVerified` เป็น false และ `speechOutputTimedOut` เป็น true ผู้ให้บริการเรียลไทม์อาจยอมรับถ้อยคำแล้ว แต่ OpenClaw ไม่เห็นไบต์เอาต์พุตใหม่ไปถึงสะพานเสียง Chrome ตรวจสอบเพิ่มเติมว่า: -- มีคีย์ผู้ให้บริการ realtime บนโฮสต์ Gateway เช่น - `OPENAI_API_KEY` หรือ `GEMINI_API_KEY` +- คีย์ผู้ให้บริการเรียลไทม์พร้อมใช้งานบนโฮสต์ Gateway เช่น `OPENAI_API_KEY` หรือ `GEMINI_API_KEY` - `BlackHole 2ch` มองเห็นได้บนโฮสต์ Chrome - `sox` มีอยู่บนโฮสต์ Chrome -- ไมโครโฟนและลำโพง Meet ถูกกำหนดเส้นทางผ่านเส้นทางเสียงเสมือนที่ OpenClaw ใช้ - `doctor` ควรแสดง `meet output routed: yes` สำหรับการเข้าร่วม Chrome realtime - ในเครื่อง +- ไมโครโฟนและลำโพง Meet ถูกกำหนดเส้นทางผ่านเส้นทางเสียงเสมือนที่ OpenClaw ใช้ `doctor` ควรแสดง `meet output routed: yes` สำหรับการเข้าร่วม Chrome ในเครื่องแบบเรียลไทม์ -`googlemeet doctor [session-id]` พิมพ์เซสชัน, Node, สถานะอยู่ในสาย, -เหตุผลของการทำงานด้วยตนเอง, การเชื่อมต่อผู้ให้บริการ realtime, `realtimeReady`, -กิจกรรมอินพุต/เอาต์พุตเสียง, timestamp เสียงล่าสุด, ตัวนับไบต์ และ URL เบราว์เซอร์ -ใช้ `googlemeet status [session-id] --json` เมื่อคุณต้องการ JSON ดิบ ใช้ -`googlemeet doctor --oauth` เมื่อคุณต้องการตรวจสอบการรีเฟรช OAuth ของ Google Meet -โดยไม่เปิดเผยโทเค็น; เพิ่ม `--meeting` หรือ `--create-space` เมื่อคุณต้องการ -หลักฐาน Google Meet API ด้วย +`googlemeet doctor [session-id]` พิมพ์เซสชัน, Node, สถานะในสาย, เหตุผลการกระทำด้วยตนเอง, การเชื่อมต่อผู้ให้บริการเรียลไทม์, `realtimeReady`, กิจกรรมอินพุต/เอาต์พุตเสียง, การประทับเวลาเสียงล่าสุด, ตัวนับไบต์ และ URL เบราว์เซอร์ ใช้ `googlemeet status [session-id] --json` เมื่อต้องการ JSON ดิบ ใช้ `googlemeet doctor --oauth` เมื่อต้องการตรวจสอบการรีเฟรช OAuth ของ Google Meet โดยไม่เปิดเผยโทเค็น; เพิ่ม `--meeting` หรือ `--create-space` เมื่อต้องการหลักฐาน Google Meet API ด้วย -หากเอเจนต์หมดเวลาและคุณเห็นแท็บ Meet เปิดอยู่แล้ว ให้ตรวจสอบแท็บนั้น -โดยไม่ต้องเปิดอีกแท็บ: +หากเอเจนต์หมดเวลาและคุณเห็นว่าแท็บ Meet เปิดอยู่แล้ว ให้ตรวจสอบแท็บนั้นโดยไม่เปิดอีกแท็บ: ```bash openclaw googlemeet recover-tab openclaw googlemeet recover-tab https://meet.google.com/abc-defg-hij ``` -การทำงานของเครื่องมือที่เทียบเท่าคือ `recover_current_tab` เครื่องมือนี้โฟกัสและตรวจสอบ -แท็บ Meet ที่มีอยู่สำหรับ transport ที่เลือก เมื่อใช้ `chrome` จะใช้การควบคุมเบราว์เซอร์ -ในเครื่องผ่าน Gateway; เมื่อใช้ `chrome-node` จะใช้ Chrome Node ที่กำหนดค่าไว้ -เครื่องมือนี้ไม่เปิดแท็บใหม่หรือสร้างเซสชันใหม่; แต่รายงานตัวบล็อกปัจจุบัน -เช่น สถานะการเข้าสู่ระบบ การอนุญาตเข้า การให้สิทธิ์ หรือการเลือกเสียง -คำสั่ง CLI คุยกับ Gateway ที่กำหนดค่าไว้ ดังนั้น Gateway ต้องทำงานอยู่; -`chrome-node` ยังต้องมี Chrome Node เชื่อมต่ออยู่ด้วย +การกระทำเครื่องมือที่เทียบเท่าคือ `recover_current_tab` โดยจะโฟกัสและตรวจสอบแท็บ Meet ที่มีอยู่สำหรับทรานสปอร์ตที่เลือก เมื่อใช้ `chrome` จะใช้การควบคุมเบราว์เซอร์ในเครื่องผ่าน Gateway; เมื่อใช้ `chrome-node` จะใช้ Node Chrome ที่กำหนดค่าไว้ คำสั่งนี้ไม่เปิดแท็บใหม่หรือสร้างเซสชันใหม่ แต่รายงานตัวขัดขวางปัจจุบัน เช่น สถานะการเข้าสู่ระบบ การรับเข้า สิทธิ์ หรือการเลือกเสียง คำสั่ง CLI คุยกับ Gateway ที่กำหนดค่าไว้ ดังนั้น Gateway ต้องกำลังทำงานอยู่; `chrome-node` ยังต้องให้ Node Chrome เชื่อมต่ออยู่ด้วย ### การตรวจสอบการตั้งค่า Twilio ล้มเหลว -`twilio-voice-call-plugin` ล้มเหลวเมื่อ `voice-call` ไม่ได้รับอนุญาตหรือไม่ได้เปิดใช้งาน -เพิ่มลงใน `plugins.allow` เปิดใช้งาน `plugins.entries.voice-call` และโหลด -Gateway ใหม่ +`twilio-voice-call-plugin` ล้มเหลวเมื่อ `voice-call` ไม่ได้รับอนุญาตหรือไม่ได้เปิดใช้งาน เพิ่มลงใน `plugins.allow`, เปิดใช้งาน `plugins.entries.voice-call` และโหลด Gateway ใหม่ -`twilio-voice-call-credentials` ล้มเหลวเมื่อแบ็กเอนด์ Twilio ไม่มี account -SID, auth token หรือหมายเลขผู้โทร ตั้งค่าเหล่านี้บนโฮสต์ Gateway: +`twilio-voice-call-credentials` ล้มเหลวเมื่อแบ็กเอนด์ Twilio ไม่มี SID บัญชี โทเค็นยืนยันตัวตน หรือหมายเลขผู้โทร ตั้งค่าสิ่งเหล่านี้บนโฮสต์ Gateway: ```bash export TWILIO_ACCOUNT_SID=AC... @@ -1416,14 +1343,9 @@ export TWILIO_AUTH_TOKEN=... export TWILIO_FROM_NUMBER=+15550001234 ``` -`twilio-voice-call-webhook` ล้มเหลวเมื่อ `voice-call` ไม่มีการเปิดเผย Webhook -สาธารณะ หรือเมื่อ `publicUrl` ชี้ไปยัง local loopback หรือพื้นที่เครือข่ายส่วนตัว -ตั้งค่า `plugins.entries.voice-call.config.publicUrl` เป็น URL ผู้ให้บริการสาธารณะ หรือ -กำหนดค่า tunnel/Tailscale exposure สำหรับ `voice-call` +`twilio-voice-call-webhook` ล้มเหลวเมื่อ `voice-call` ไม่มีการเปิดเผย Webhook สาธารณะ หรือเมื่อ `publicUrl` ชี้ไปยัง local loopback หรือพื้นที่เครือข่ายส่วนตัว ตั้งค่า `plugins.entries.voice-call.config.publicUrl` เป็น URL ผู้ให้บริการสาธารณะ หรือกำหนดค่าทันเนล/การเปิดเผยผ่าน Tailscale สำหรับ `voice-call` -URL แบบ loopback และส่วนตัวไม่ถูกต้องสำหรับ callback ของผู้ให้บริการโทรศัพท์ อย่าใช้ -`localhost`, `127.0.0.1`, `0.0.0.0`, `10.x`, `172.16.x`-`172.31.x`, -`192.168.x`, `169.254.x`, `fc00::/7` หรือ `fd00::/8` เป็น `publicUrl` +URL แบบ loopback และส่วนตัวไม่ถูกต้องสำหรับคอลแบ็กของผู้ให้บริการเครือข่าย อย่าใช้ `localhost`, `127.0.0.1`, `0.0.0.0`, `10.x`, `172.16.x`-`172.31.x`, `192.168.x`, `169.254.x`, `fc00::/7` หรือ `fd00::/8` เป็น `publicUrl` สำหรับ URL สาธารณะที่เสถียร: @@ -1444,8 +1366,8 @@ URL แบบ loopback และส่วนตัวไม่ถูกต้อ } ``` -สำหรับการพัฒนาในเครื่อง ให้ใช้ tunnel หรือ Tailscale exposure แทน URL โฮสต์ -ส่วนตัว: +สำหรับการพัฒนาในเครื่อง ให้ใช้อุโมงค์หรือการเปิดเผยผ่าน Tailscale แทน URL +โฮสต์ส่วนตัว: ```json5 { @@ -1463,7 +1385,7 @@ URL แบบ loopback และส่วนตัวไม่ถูกต้อ } ``` -จากนั้นรีสตาร์ตหรือโหลด Gateway ใหม่และรัน: +จากนั้นรีสตาร์ตหรือโหลด Gateway ใหม่ แล้วรัน: ```bash openclaw googlemeet setup --transport twilio @@ -1471,23 +1393,22 @@ openclaw voicecall setup openclaw voicecall smoke ``` -`voicecall smoke` เป็นการตรวจสอบความพร้อมเท่านั้นโดยค่าเริ่มต้น หากต้องการ dry-run -หมายเลขเฉพาะ: +โดยค่าเริ่มต้น `voicecall smoke` ใช้เพื่อตรวจความพร้อมเท่านั้น หากต้องการ dry-run กับหมายเลขเฉพาะ: ```bash openclaw voicecall smoke --to "+15555550123" ``` -เพิ่ม `--yes` เฉพาะเมื่อคุณตั้งใจจะโทรแจ้งเตือนขาออกแบบสด: +เพิ่ม `--yes` เฉพาะเมื่อคุณตั้งใจจะโทรแจ้งเตือนขาออกจริง: ```bash openclaw voicecall smoke --to "+15555550123" --yes ``` -### สาย Twilio เริ่มแล้วแต่ไม่เคยเข้าสู่การประชุม +### การโทร Twilio เริ่มแล้วแต่ไม่เคยเข้าสู่การประชุม -ยืนยันว่าอีเวนต์ Meet เปิดเผยรายละเอียดการโทรเข้าโทรศัพท์ ส่งหมายเลขโทรเข้า -และ PIN ที่ถูกต้อง หรือกำหนดลำดับ DTMF แบบกำหนดเอง: +ยืนยันว่าอีเวนต์ Meet เปิดเผยรายละเอียดการโทรเข้า ส่งหมายเลขโทรเข้าและ PIN +ที่ตรงกัน หรือส่งลำดับ DTMF แบบกำหนดเอง: ```bash openclaw googlemeet join https://meet.google.com/abc-defg-hij \ @@ -1496,73 +1417,80 @@ openclaw googlemeet join https://meet.google.com/abc-defg-hij \ --dtmf-sequence ww123456# ``` -ใช้ `w` นำหน้าหรือจุลภาคใน `--dtmf-sequence` หากผู้ให้บริการต้องการการหยุดพัก +ใช้ `w` นำหน้าหรือคอมมาใน `--dtmf-sequence` หากผู้ให้บริการต้องการหยุดพัก ก่อนป้อน PIN -หากสร้างสายโทรศัพท์แล้วแต่รายชื่อผู้เข้าร่วม Meet ไม่เคยแสดงผู้เข้าร่วมแบบโทรเข้า: +หากสร้างสายโทรศัพท์แล้ว แต่รายชื่อผู้เข้าร่วมของ Meet ไม่เคยแสดงผู้เข้าร่วม +ที่โทรเข้า: - รัน `openclaw googlemeet doctor ` เพื่อยืนยัน ID สาย Twilio - ที่มอบหมายไว้ ตรวจว่า DTMF เข้าคิวแล้วหรือไม่ และตรวจว่ามีการร้องขอคำทักทายแนะนำตัวหรือไม่ -- รัน `openclaw voicecall status --call-id ` และยืนยันว่าสายยังคงใช้งานอยู่ -- รัน `openclaw voicecall tail` และตรวจว่า Webhook ของ Twilio มาถึง Gateway -- รัน `openclaw logs --follow` และมองหาลำดับ Twilio Meet: Google + ที่มอบหมาย ว่า DTMF ถูกเข้าคิวหรือไม่ และมีการขอคำทักทายเริ่มต้นหรือไม่ +- รัน `openclaw voicecall status --call-id ` และยืนยันว่าสายยังทำงานอยู่ +- รัน `openclaw voicecall tail` และตรวจว่า Webhook ของ Twilio มาถึง + Gateway +- รัน `openclaw logs --follow` แล้วมองหาลำดับ Twilio Meet: Google Meet มอบหมายการเข้าร่วม, Voice Call เริ่มขาโทรศัพท์, Google Meet รอ `voiceCall.dtmfDelayMs`, ส่ง DTMF ด้วย `voicecall.dtmf`, รอ - `voiceCall.postDtmfSpeechDelayMs` จากนั้นร้องขอคำพูดแนะนำตัวด้วย + `voiceCall.postDtmfSpeechDelayMs`, จากนั้นขอเสียงแนะนำตัวด้วย `voicecall.speak` -- รัน `openclaw googlemeet setup --transport twilio` อีกครั้ง; ต้องมีการตรวจสอบการตั้งค่า - เป็นสีเขียว แต่ไม่ได้พิสูจน์ว่าลำดับ PIN การประชุมถูกต้อง +- รัน `openclaw googlemeet setup --transport twilio` อีกครั้ง; การตรวจ setup + ที่ผ่านเป็นสีเขียวเป็นสิ่งจำเป็น แต่ไม่ได้พิสูจน์ว่าลำดับ PIN ของการประชุมถูกต้อง - ยืนยันว่าหมายเลขโทรเข้าเป็นของคำเชิญและภูมิภาค Meet เดียวกันกับ PIN -- เพิ่ม `voiceCall.dtmfDelayMs` หาก Meet รับสายช้า หรือบันทึกถอดเสียงของสาย - ยังแสดงพรอมป์ให้ป้อน PIN หลังจากส่ง DTMF แล้ว +- เพิ่ม `voiceCall.dtmfDelayMs` หาก Meet รับสายช้าหรือบันทึกถอดเสียงของสายยังแสดงพรอมต์ที่ขอ PIN หลังจากส่ง DTMF แล้ว - หากผู้เข้าร่วมเข้าร่วมแล้วแต่คุณไม่ได้ยินคำทักทาย ให้ตรวจ - `openclaw logs --follow` เพื่อดูคำขอ `voicecall.speak` หลัง DTMF และ - การเล่น TTS แบบ media-stream หรือ fallback `` ของ Twilio หากบันทึกถอดเสียงของสาย - ยังมี "enter the meeting PIN" แสดงว่าขาโทรศัพท์ยังไม่ได้เข้าห้อง Meet - ดังนั้นผู้เข้าร่วมการประชุมจะยังไม่ได้ยินเสียงพูด + `openclaw logs --follow` สำหรับคำขอ `voicecall.speak` หลัง DTMF และ + การเล่น TTS ผ่าน media-stream หรือ fallback `` ของ Twilio หากบันทึก + ถอดเสียงของสายยังมีข้อความ "enter the meeting PIN" แสดงว่าขาโทรศัพท์ยังไม่ได้ + เข้าห้อง Meet ดังนั้นผู้เข้าร่วมประชุมจะไม่ได้ยินเสียงพูด -หาก Webhook ไม่มาถึง ให้ดีบัก Voice Call Plugin ก่อน: ผู้ให้บริการต้อง -เข้าถึง `plugins.entries.voice-call.config.publicUrl` หรือ tunnel ที่กำหนดค่าไว้ได้ -ดู [การแก้ปัญหาการโทรด้วยเสียง](/th/plugins/voice-call#troubleshooting) +หาก Webhook ไม่มาถึง ให้ดีบัก Plugin Voice Call ก่อน: ผู้ให้บริการต้องเข้าถึง +`plugins.entries.voice-call.config.publicUrl` หรืออุโมงค์ที่กำหนดค่าไว้ +ดู [การแก้ไขปัญหาการโทรด้วยเสียง](/th/plugins/voice-call#troubleshooting) ## หมายเหตุ -API สื่ออย่างเป็นทางการของ Google Meet เน้นการรับสื่อ ดังนั้นการพูดเข้าไปในสาย Meet -ยังคงต้องมีเส้นทางของผู้เข้าร่วม Plugin นี้ทำให้ขอบเขตนั้นมองเห็นได้ชัดเจน: -Chrome จัดการการเข้าร่วมผ่านเบราว์เซอร์และการกำหนดเส้นทางเสียงภายในเครื่อง; Twilio จัดการ -การเข้าร่วมด้วยการโทรเข้า +API สื่ออย่างเป็นทางการของ Google Meet มุ่งเน้นการรับ ดังนั้นการพูดเข้าไปในสาย +Meet ยังต้องมีเส้นทางผู้เข้าร่วม Plugin นี้ทำให้ขอบเขตนั้นมองเห็นได้: +Chrome จัดการการเข้าร่วมผ่านเบราว์เซอร์และการกำหนดเส้นทางเสียงในเครื่อง; Twilio +จัดการการเข้าร่วมโดยโทรศัพท์โทรเข้า -โหมดตอบกลับด้วยเสียงของ Chrome ต้องใช้ `BlackHole 2ch` พร้อมอย่างใดอย่างหนึ่งต่อไปนี้: +โหมด talk-back ของ Chrome ต้องใช้ `BlackHole 2ch` พร้อมอย่างใดอย่างหนึ่งต่อไปนี้: - `chrome.audioInputCommand` พร้อม `chrome.audioOutputCommand`: OpenClaw เป็นเจ้าของ - bridge และ pipe เสียงใน `chrome.audioFormat` ระหว่างคำสั่งเหล่านั้นกับ - ผู้ให้บริการที่เลือก โหมด agent ใช้การถอดเสียงแบบเรียลไทม์ร่วมกับ TTS ปกติ; - โหมด bidi ใช้ผู้ให้บริการเสียงแบบเรียลไทม์ เส้นทาง Chrome เริ่มต้นคือ 24 kHz - PCM16; 8 kHz G.711 mu-law ยังคงพร้อมใช้งานสำหรับคู่คำสั่งรุ่นเดิม -- `chrome.audioBridgeCommand`: คำสั่ง bridge ภายนอกเป็นเจ้าของเส้นทางเสียงภายในเครื่อง - ทั้งหมด และต้องออกหลังจากเริ่มหรือยืนยัน daemon ของตัวเองแล้ว รายการนี้ใช้ได้เฉพาะกับ - `bidi` เพราะโหมด `agent` ต้องเข้าถึงคู่คำสั่งโดยตรงสำหรับ TTS + bridge และส่งผ่านเสียงใน `chrome.audioFormat` ระหว่างคำสั่งเหล่านั้นกับผู้ให้บริการ + ที่เลือก โหมด Agent ใช้การถอดเสียงแบบเรียลไทม์พร้อม TTS ปกติ; + โหมด bidi ใช้ผู้ให้บริการเสียงแบบเรียลไทม์ เส้นทาง Chrome เริ่มต้นคือ PCM16 + 24 kHz พร้อม `chrome.audioBufferBytes: 4096`; G.711 mu-law 8 kHz ยังคง + ใช้งานได้สำหรับคู่คำสั่งแบบเดิม +- `chrome.audioBridgeCommand`: คำสั่ง bridge ภายนอกเป็นเจ้าของเส้นทางเสียงในเครื่องทั้งหมด + และต้องออกหลังจากเริ่มหรือยืนยัน daemon ของตน วิธีนี้ใช้ได้เฉพาะกับ `bidi` + เพราะโหมด `agent` ต้องเข้าถึงคู่คำสั่งโดยตรงสำหรับ TTS -เพื่อให้ได้เสียง duplex ที่สะอาด ให้กำหนดเส้นทางเอาต์พุต Meet และไมโครโฟน Meet ผ่าน -อุปกรณ์เสมือนแยกกัน หรือกราฟอุปกรณ์เสมือนแบบ Loopback-style อุปกรณ์ BlackHole เดียวที่ใช้ร่วมกัน -อาจสะท้อนเสียงผู้เข้าร่วมคนอื่นกลับเข้าไปในสายได้ +เมื่อ Agent เรียกเครื่องมือ `google_meet` ในโหมด Agent เซสชันที่ปรึกษาการประชุม +จะ fork บันทึกบทสนทนาปัจจุบันของผู้เรียกก่อนตอบเสียงผู้เข้าร่วม เซสชัน Meet +ยังคงแยกอยู่ (`agent::subagent:google-meet:`) +ดังนั้นการติดตามผลของการประชุมจะไม่แก้ไขบันทึกบทสนทนาของผู้เรียกโดยตรง -เมื่อใช้ bridge Chrome แบบคู่คำสั่ง `chrome.bargeInInputCommand` สามารถฟัง -ไมโครโฟนภายในเครื่องแยกต่างหากและล้างเสียงเล่นกลับของผู้ช่วยเมื่อมนุษย์เริ่ม -พูด วิธีนี้ทำให้เสียงพูดของมนุษย์มาก่อนเอาต์พุตของผู้ช่วย แม้เมื่ออินพุต -BlackHole loopback ที่ใช้ร่วมกันถูกระงับชั่วคราวระหว่างการเล่นกลับของผู้ช่วย -เช่นเดียวกับ `chrome.audioInputCommand` และ `chrome.audioOutputCommand` รายการนี้เป็น -คำสั่งภายในเครื่องที่ผู้ปฏิบัติงานกำหนดค่า ใช้เส้นทางคำสั่งที่เชื่อถือได้อย่างชัดเจนหรือ -รายการอาร์กิวเมนต์ และอย่าชี้ไปยังสคริปต์จากตำแหน่งที่ไม่น่าเชื่อถือ +เพื่อให้ได้เสียงสองทางที่สะอาด ให้กำหนดเส้นทางเอาต์พุต Meet และไมโครโฟน Meet +ผ่านอุปกรณ์เสมือนแยกกันหรือกราฟอุปกรณ์เสมือนแบบ Loopback อุปกรณ์ BlackHole +ที่แชร์เพียงตัวเดียวอาจสะท้อนเสียงผู้เข้าร่วมคนอื่นกลับเข้าไปในสาย -`googlemeet speak` จะทริกเกอร์ bridge เสียงตอบกลับที่ใช้งานอยู่สำหรับเซสชัน Chrome -`googlemeet leave` จะหยุด bridge นั้น สำหรับเซสชัน Twilio ที่มอบหมายผ่าน Voice Call Plugin, -`leave` จะวางสายการโทรด้วยเสียงเบื้องหลังด้วย -ใช้ `googlemeet end-active-conference` เมื่อคุณต้องการปิด -การประชุม Google Meet ที่ใช้งานอยู่สำหรับพื้นที่ที่จัดการด้วย API ด้วย +เมื่อใช้ Chrome bridge แบบคู่คำสั่ง `chrome.bargeInInputCommand` สามารถฟัง +ไมโครโฟนในเครื่องแยกต่างหากและล้างการเล่นเสียงของผู้ช่วยเมื่อมนุษย์เริ่มพูด +วิธีนี้ทำให้เสียงพูดของมนุษย์มาก่อนเอาต์พุตของผู้ช่วย แม้อินพุต local loopback +ของ BlackHole ที่แชร์จะถูกระงับชั่วคราวระหว่างการเล่นเสียงของผู้ช่วยก็ตาม +เช่นเดียวกับ `chrome.audioInputCommand` และ `chrome.audioOutputCommand` คำสั่งนี้เป็น +คำสั่งในเครื่องที่ operator กำหนดค่าไว้ ใช้เส้นทางคำสั่งหรือรายการอาร์กิวเมนต์ +ที่เชื่อถือได้อย่างชัดเจน และอย่าชี้ไปยังสคริปต์จากตำแหน่งที่ไม่น่าเชื่อถือ + +`googlemeet speak` จะเรียก bridge เสียง talk-back ที่ทำงานอยู่สำหรับเซสชัน +Chrome `googlemeet leave` จะหยุด bridge นั้น สำหรับเซสชัน Twilio ที่มอบหมาย +ผ่าน Plugin Voice Call, `leave` จะวางสายเสียงพื้นฐานด้วย ใช้ +`googlemeet end-active-conference` เมื่อคุณต้องการปิดการประชุม Google Meet +ที่ทำงานอยู่สำหรับพื้นที่ที่จัดการผ่าน API ด้วย ## ที่เกี่ยวข้อง -- [Voice Call Plugin](/th/plugins/voice-call) +- [Plugin โทรด้วยเสียง](/th/plugins/voice-call) - [โหมดพูดคุย](/th/nodes/talk) - [การสร้าง Plugin](/th/plugins/building-plugins) diff --git a/docs/th/plugins/voice-call.md b/docs/th/plugins/voice-call.md index 2df3f6ebd..c21ae3a55 100644 --- a/docs/th/plugins/voice-call.md +++ b/docs/th/plugins/voice-call.md @@ -2,26 +2,26 @@ read_when: - คุณต้องการโทรออกด้วยเสียงจาก OpenClaw - คุณกำลังกำหนดค่าหรือพัฒนา Plugin การโทรด้วยเสียง - - คุณต้องการเสียงแบบเรียลไทม์หรือการถอดเสียงแบบสตรีมบนระบบโทรศัพท์ + - คุณต้องการเสียงแบบเรียลไทม์หรือการถอดเสียงแบบสตรีมมิงบนระบบโทรศัพท์ sidebarTitle: Voice call -summary: โทรออกและรับสายโทรเข้าด้วยเสียงผ่าน Twilio, Telnyx หรือ Plivo พร้อมตัวเลือกสำหรับเสียงแบบเรียลไทม์และการถอดเสียงแบบสตรีมมิง +summary: โทรออกและรับสายเสียงขาเข้าผ่าน Twilio, Telnyx หรือ Plivo พร้อมตัวเลือกเสียงแบบเรียลไทม์และการถอดเสียงแบบสตรีมมิง title: Plugin การโทรด้วยเสียง x-i18n: - generated_at: "2026-05-02T22:22:12Z" + generated_at: "2026-05-04T07:06:08Z" model: gpt-5.5 provider: openai - source_hash: 18a9a0d7095ec92036b516cc26c69219a0a2fd9bb8e0cb2e7509123bb4f3f65a + source_hash: 8ec2c22dcc9073572963744685a432328787bcedb14025e0326c20d9d842f857 source_path: plugins/voice-call.md workflow: 16 --- -ปลั๊กอินสำหรับให้ OpenClaw โทรด้วยเสียง รองรับการแจ้งเตือนขาออก, +การโทรด้วยเสียงสำหรับ OpenClaw ผ่าน Plugin รองรับการแจ้งเตือนขาออก, การสนทนาหลายรอบ, เสียงเรียลไทม์แบบฟูลดูเพล็กซ์, การถอดเสียงแบบสตรีมมิง, -และสายขาเข้าพร้อมนโยบายรายการอนุญาต +และสายเรียกเข้าพร้อมนโยบาย allowlist **ผู้ให้บริการปัจจุบัน:** `twilio` (Programmable Voice + Media Streams), `telnyx` (Call Control v2), `plivo` (Voice API + XML transfer + GetInput -speech), `mock` (การพัฒนา/ไม่มีเครือข่าย) +speech), `mock` (dev/no network). Plugin Voice Call ทำงาน **ภายในกระบวนการ Gateway** หากคุณใช้ @@ -32,14 +32,14 @@ Gateway จากนั้นรีสตาร์ท Gateway เพื่อโ ## เริ่มต้นอย่างรวดเร็ว - + - + ```bash openclaw plugins install @openclaw/voice-call ``` - + ```bash PLUGIN_SRC=./path/to/local/voice-call-plugin openclaw plugins install "$PLUGIN_SRC" @@ -48,36 +48,36 @@ Gateway จากนั้นรีสตาร์ท Gateway เพื่อโ - ใช้แพ็กเกจเปล่าเพื่อตามแท็กรุ่นทางการปัจจุบัน ตรึงเป็น + ใช้แพ็กเกจเปล่าเพื่อตามแท็กรีลีสอย่างเป็นทางการปัจจุบัน ปักหมุด เวอร์ชันที่แน่นอนเฉพาะเมื่อคุณต้องการการติดตั้งที่ทำซ้ำได้ รีสตาร์ท Gateway หลังจากนั้นเพื่อให้ Plugin โหลด - - ตั้งค่าคอนฟิกใต้ `plugins.entries.voice-call.config` (ดู - [การกำหนดค่า](#configuration) ด้านล่างสำหรับรูปแบบเต็ม) อย่างน้อยต้องมี: - `provider`, ข้อมูลรับรองของผู้ให้บริการ, `fromNumber`, และ URL ของ Webhook - ที่เข้าถึงได้สาธารณะ + + ตั้งค่าคอนฟิกภายใต้ `plugins.entries.voice-call.config` (ดู + [การกำหนดค่า](#configuration) ด้านล่างสำหรับโครงสร้างทั้งหมด) อย่างน้อยต้องมี: + `provider`, ข้อมูลประจำตัวของผู้ให้บริการ, `fromNumber`, และ URL Webhook + ที่เข้าถึงได้แบบสาธารณะ - + ```bash openclaw voicecall setup ``` เอาต์พุตเริ่มต้นอ่านได้ในบันทึกแชตและเทอร์มินัล โดยตรวจสอบ - การเปิดใช้ Plugin, ข้อมูลรับรองของผู้ให้บริการ, การเปิดเผย Webhook, - และว่ามีโหมดเสียงเพียงโหมดเดียว (`streaming` หรือ `realtime`) ที่เปิดอยู่ ใช้ + การเปิดใช้ Plugin, ข้อมูลประจำตัวของผู้ให้บริการ, การเปิดเผย Webhook, + และมีโหมดเสียงเพียงโหมดเดียว (`streaming` หรือ `realtime`) ที่ใช้งานอยู่ ใช้ `--json` สำหรับสคริปต์ - + ```bash openclaw voicecall smoke openclaw voicecall smoke --to "+15555550123" ``` - ทั้งสองรายการเป็น dry run โดยค่าเริ่มต้น เพิ่ม `--yes` เพื่อโทรแจ้งเตือน + ทั้งสองคำสั่งเป็น dry run โดยค่าเริ่มต้น เพิ่ม `--yes` เพื่อโทรแจ้งเตือน ขาออกสั้น ๆ จริง: ```bash @@ -88,21 +88,21 @@ Gateway จากนั้นรีสตาร์ท Gateway เพื่อโ -สำหรับ Twilio, Telnyx และ Plivo การตั้งค่าต้องแก้ค่าเป็น **URL ของ Webhook สาธารณะ** -หาก `publicUrl`, URL ของ tunnel, URL ของ Tailscale หรือ serve fallback -แก้ค่าเป็น loopback หรือพื้นที่เครือข่ายส่วนตัว การตั้งค่าจะล้มเหลวแทนที่จะ -เริ่มผู้ให้บริการที่รับ Webhook จากผู้ให้บริการเครือข่ายไม่ได้ +สำหรับ Twilio, Telnyx และ Plivo การตั้งค่าต้อง resolve เป็น **URL Webhook สาธารณะ** +หาก `publicUrl`, URL tunnel, URL Tailscale หรือ serve fallback +resolve เป็น loopback หรือพื้นที่เครือข่ายส่วนตัว การตั้งค่าจะล้มเหลวแทนที่จะ +เริ่มผู้ให้บริการที่ไม่สามารถรับ carrier webhooks ได้ ## การกำหนดค่า -หาก `enabled: true` แต่ผู้ให้บริการที่เลือกขาดข้อมูลรับรอง, -การเริ่มต้น Gateway จะบันทึกคำเตือนว่าการตั้งค่ายังไม่สมบูรณ์พร้อมคีย์ที่ขาด -และข้ามการเริ่ม runtime คำสั่ง, การเรียก RPC และเครื่องมือ agent ยังคง -คืนค่าการกำหนดค่าผู้ให้บริการที่ขาดอย่างตรงตัวเมื่อใช้งาน +หาก `enabled: true` แต่ผู้ให้บริการที่เลือกไม่มีข้อมูลประจำตัว +การเริ่มต้น Gateway จะบันทึกคำเตือนว่าการตั้งค่าไม่สมบูรณ์พร้อมคีย์ที่ขาดหายไป และ +ข้ามการเริ่ม runtime คำสั่ง, การเรียก RPC และเครื่องมือ agent ยังคง +ส่งคืนคอนฟิกผู้ให้บริการที่ขาดหายไปอย่างแม่นยำเมื่อใช้งาน -ข้อมูลรับรอง voice-call รองรับ SecretRefs `plugins.entries.voice-call.config.twilio.authToken`, `plugins.entries.voice-call.config.realtime.providers.*.apiKey`, `plugins.entries.voice-call.config.streaming.providers.*.apiKey`, และ `plugins.entries.voice-call.config.tts.providers.*.apiKey` แก้ค่าผ่านพื้นผิว SecretRef มาตรฐาน; ดู [พื้นผิวข้อมูลรับรอง SecretRef](/th/reference/secretref-credential-surface) +ข้อมูลประจำตัว voice-call รองรับ SecretRefs `plugins.entries.voice-call.config.twilio.authToken`, `plugins.entries.voice-call.config.realtime.providers.*.apiKey`, `plugins.entries.voice-call.config.streaming.providers.*.apiKey` และ `plugins.entries.voice-call.config.tts.providers.*.apiKey` จะ resolve ผ่านพื้นผิว SecretRef มาตรฐาน; ดู [พื้นผิวข้อมูลประจำตัว SecretRef](/th/reference/secretref-credential-surface) ```json5 @@ -175,31 +175,31 @@ Gateway จากนั้นรีสตาร์ท Gateway เพื่อโ ``` - - - Twilio, Telnyx และ Plivo ทั้งหมดต้องใช้ URL ของ Webhook ที่ **เข้าถึงได้สาธารณะ** - - `mock` เป็นผู้ให้บริการสำหรับการพัฒนาในเครื่อง (ไม่มีการเรียกเครือข่าย) + + - Twilio, Telnyx และ Plivo ทั้งหมดต้องใช้ URL Webhook ที่ **เข้าถึงได้แบบสาธารณะ** + - `mock` คือผู้ให้บริการ dev ในเครื่อง (ไม่มีการเรียกเครือข่าย) - Telnyx ต้องใช้ `telnyx.publicKey` (หรือ `TELNYX_PUBLIC_KEY`) เว้นแต่ `skipSignatureVerification` เป็น true - `skipSignatureVerification` ใช้สำหรับการทดสอบในเครื่องเท่านั้น - - บนระดับฟรีของ ngrok ให้ตั้งค่า `publicUrl` เป็น URL ของ ngrok ที่แน่นอน; การตรวจสอบลายเซ็นจะบังคับใช้เสมอ - - `tunnel.allowNgrokFreeTierLoopbackBypass: true` อนุญาต Webhook ของ Twilio ที่มีลายเซ็นไม่ถูกต้อง **เฉพาะ** เมื่อ `tunnel.provider="ngrok"` และ `serve.bind` เป็น loopback (agent ในเครื่องของ ngrok) สำหรับการพัฒนาในเครื่องเท่านั้น - - URL ระดับฟรีของ Ngrok อาจเปลี่ยนหรือเพิ่มพฤติกรรม interstitial; หาก `publicUrl` เบี่ยงไป ลายเซ็นของ Twilio จะล้มเหลว สำหรับโปรดักชัน: ควรใช้โดเมนที่เสถียรหรือ Tailscale funnel + - ใน ngrok ระดับฟรี ให้ตั้ง `publicUrl` เป็น URL ngrok ที่แน่นอน; การตรวจสอบลายเซ็นจะถูกบังคับใช้เสมอ + - `tunnel.allowNgrokFreeTierLoopbackBypass: true` อนุญาต Twilio webhooks ที่มีลายเซ็นไม่ถูกต้อง **เฉพาะ** เมื่อ `tunnel.provider="ngrok"` และ `serve.bind` เป็น loopback (ngrok local agent) เท่านั้น สำหรับ dev ในเครื่องเท่านั้น + - URL ระดับฟรีของ Ngrok อาจเปลี่ยนหรือเพิ่มพฤติกรรม interstitial ได้; หาก `publicUrl` เคลื่อนออกไป ลายเซ็น Twilio จะล้มเหลว Production: แนะนำให้ใช้โดเมนที่เสถียรหรือ Tailscale funnel - - - `streaming.preStartTimeoutMs` ปิดซ็อกเก็ตที่ไม่เคยส่งเฟรม `start` ที่ถูกต้อง - - `streaming.maxPendingConnections` จำกัดจำนวนซ็อกเก็ต pre-start ที่ยังไม่ตรวจสอบสิทธิ์ทั้งหมด - - `streaming.maxPendingConnectionsPerIp` จำกัดซ็อกเก็ต pre-start ที่ยังไม่ตรวจสอบสิทธิ์ต่อ IP ต้นทาง - - `streaming.maxConnections` จำกัดจำนวนซ็อกเก็ต media stream ที่เปิดทั้งหมด (pending + active) + + - `streaming.preStartTimeoutMs` ปิด socket ที่ไม่เคยส่ง frame `start` ที่ถูกต้อง + - `streaming.maxPendingConnections` จำกัดจำนวน socket pre-start ที่ยังไม่ได้ยืนยันตัวตนทั้งหมด + - `streaming.maxPendingConnectionsPerIp` จำกัดจำนวน socket pre-start ที่ยังไม่ได้ยืนยันตัวตนต่อ IP ต้นทาง + - `streaming.maxConnections` จำกัดจำนวน socket media stream ที่เปิดอยู่ทั้งหมด (pending + active) - + คอนฟิกเก่าที่ใช้ `provider: "log"`, `twilio.from` หรือคีย์ OpenAI - `streaming.*` แบบเดิม จะถูกเขียนใหม่โดย `openclaw doctor --fix` - runtime fallback ยังคงยอมรับคีย์ voice-call เก่าในตอนนี้ แต่ - เส้นทางการเขียนใหม่คือ `openclaw doctor --fix` และ compat shim - เป็นเพียงชั่วคราว + `streaming.*` แบบ legacy จะถูกเขียนใหม่โดย `openclaw doctor --fix` + Runtime fallback ยังยอมรับคีย์ voice-call เก่าได้ในตอนนี้ แต่ + เส้นทางการเขียนใหม่คือ `openclaw doctor --fix` และ compat shim เป็น + ชั่วคราว - คีย์สตรีมมิงที่ย้ายโดยอัตโนมัติ: + คีย์ streaming ที่ย้ายอัตโนมัติ: - `streaming.sttProvider` → `streaming.provider` - `streaming.openaiApiKey` → `streaming.providers.openai.apiKey` @@ -212,32 +212,33 @@ Gateway จากนั้นรีสตาร์ท Gateway เพื่อโ ## ขอบเขตเซสชัน -โดยค่าเริ่มต้น Voice Call ใช้ `sessionScope: "per-phone"` เพื่อให้การโทรซ้ำจาก -ผู้โทรคนเดิมคงหน่วยความจำการสนทนาไว้ ตั้งค่า `sessionScope: "per-call"` เมื่อ -การโทรของผู้ให้บริการเครือข่ายแต่ละครั้งควรเริ่มด้วยบริบทใหม่ เช่น แผนกต้อนรับ, -การจอง, IVR หรือโฟลว์บริดจ์ Google Meet ที่หมายเลขโทรศัพท์เดียวกันอาจ -แทนการประชุมคนละครั้ง +โดยค่าเริ่มต้น Voice Call ใช้ `sessionScope: "per-phone"` เพื่อให้สายซ้ำจาก +ผู้โทรรายเดิมคงหน่วยความจำการสนทนาไว้ ตั้ง `sessionScope: "per-call"` เมื่อ +แต่ละ carrier call ควรเริ่มด้วยบริบทใหม่ เช่น งานต้อนรับ, +การจอง, IVR หรือ flow สะพาน Google Meet ที่หมายเลขโทรศัพท์เดียวกันอาจ +แทนการประชุมคนละรายการ -## การสนทนาด้วยเสียงเรียลไทม์ +## การสนทนาด้วยเสียงแบบเรียลไทม์ -`realtime` เลือกผู้ให้บริการเสียงเรียลไทม์แบบฟูลดูเพล็กซ์สำหรับเสียงสดของสายโทร -แยกจาก `streaming` ซึ่งส่งต่อเสียงไปยังผู้ให้บริการถอดเสียงเรียลไทม์เท่านั้น +`realtime` เลือกผู้ให้บริการเสียงเรียลไทม์แบบฟูลดูเพล็กซ์สำหรับเสียงการโทรสด +โดยแยกจาก `streaming` ซึ่งทำหน้าที่ส่งต่อเสียงไปยัง +ผู้ให้บริการถอดเสียงแบบเรียลไทม์เท่านั้น -ไม่สามารถรวม `realtime.enabled` กับ `streaming.enabled` ได้ เลือก -โหมดเสียงหนึ่งโหมดต่อสาย +`realtime.enabled` ไม่สามารถใช้ร่วมกับ `streaming.enabled` ได้ เลือก +โหมดเสียงหนึ่งโหมดต่อการโทร พฤติกรรม runtime ปัจจุบัน: - รองรับ `realtime.enabled` สำหรับ Twilio Media Streams -- `realtime.provider` เป็นตัวเลือก หากไม่ตั้งค่า Voice Call จะใช้ผู้ให้บริการเสียงเรียลไทม์ที่ลงทะเบียนไว้รายแรก -- ผู้ให้บริการเสียงเรียลไทม์ที่รวมมา: Google Gemini Live (`google`) และ OpenAI (`openai`) ซึ่งลงทะเบียนโดย Plugin ของผู้ให้บริการเหล่านั้น -- คอนฟิกดิบที่ผู้ให้บริการเป็นเจ้าของอยู่ใต้ `realtime.providers.` -- Voice Call เปิดเผยเครื่องมือเรียลไทม์ `openclaw_agent_consult` ที่ใช้ร่วมกันโดยค่าเริ่มต้น โมเดลเรียลไทม์สามารถเรียกใช้เมื่อผู้โทรขอการให้เหตุผลที่ลึกขึ้น, ข้อมูลปัจจุบัน หรือเครื่องมือ OpenClaw ปกติ -- `realtime.fastContext.enabled` ปิดโดยค่าเริ่มต้น เมื่อเปิดใช้ Voice Call จะค้นหาบริบทหน่วยความจำ/เซสชันที่ทำดัชนีไว้สำหรับคำถาม consult ก่อน และคืน snippet เหล่านั้นให้โมเดลเรียลไทม์ภายใน `realtime.fastContext.timeoutMs` ก่อน fallback ไปยัง consult agent เต็มรูปแบบเฉพาะเมื่อ `realtime.fastContext.fallbackToConsult` เป็น true +- `realtime.provider` เป็นตัวเลือก หากไม่ได้ตั้งค่า Voice Call จะใช้ผู้ให้บริการเสียงเรียลไทม์รายแรกที่ลงทะเบียนไว้ +- ผู้ให้บริการเสียงเรียลไทม์ที่ bundled: Google Gemini Live (`google`) และ OpenAI (`openai`) ซึ่งลงทะเบียนโดย Plugin ผู้ให้บริการของตน +- คอนฟิกดิบที่ผู้ให้บริการเป็นเจ้าของอยู่ภายใต้ `realtime.providers.` +- Voice Call เปิดเผยเครื่องมือเรียลไทม์ร่วม `openclaw_agent_consult` โดยค่าเริ่มต้น โมเดลเรียลไทม์สามารถเรียกใช้ได้เมื่อผู้โทรขอการให้เหตุผลเชิงลึก ข้อมูลปัจจุบัน หรือเครื่องมือ OpenClaw ปกติ +- `realtime.fastContext.enabled` ปิดโดยค่าเริ่มต้น เมื่อเปิดใช้งาน Voice Call จะค้นหาหน่วยความจำ/บริบทเซสชันที่ทำดัชนีไว้สำหรับคำถาม consult ก่อน และส่งคืน snippet เหล่านั้นให้โมเดลเรียลไทม์ภายใน `realtime.fastContext.timeoutMs` ก่อน fallback ไปยัง consult agent เต็มรูปแบบเฉพาะเมื่อ `realtime.fastContext.fallbackToConsult` เป็น true - หาก `realtime.provider` ชี้ไปยังผู้ให้บริการที่ไม่ได้ลงทะเบียน หรือไม่มีผู้ให้บริการเสียงเรียลไทม์ที่ลงทะเบียนเลย Voice Call จะบันทึกคำเตือนและข้ามสื่อเรียลไทม์แทนที่จะทำให้ Plugin ทั้งหมดล้มเหลว -- คีย์เซสชัน consult ใช้เซสชันสายโทรที่เก็บไว้เมื่อมี จากนั้น fallback ไปยัง `sessionScope` ที่กำหนดค่าไว้ (`per-phone` โดยค่าเริ่มต้น หรือ `per-call` สำหรับสายที่แยกบริบท) +- คีย์เซสชัน consult ใช้เซสชันการโทรที่เก็บไว้เมื่อมี จากนั้น fallback ไปยัง `sessionScope` ที่กำหนดค่าไว้ (`per-phone` โดยค่าเริ่มต้น หรือ `per-call` สำหรับการโทรที่แยกบริบท) ### นโยบายเครื่องมือ @@ -245,17 +246,20 @@ Gateway จากนั้นรีสตาร์ท Gateway เพื่อโ | นโยบาย | พฤติกรรม | | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | -| `safe-read-only` | เปิดเผยเครื่องมือ consult และจำกัด agent ปกติให้ใช้ `read`, `web_search`, `web_fetch`, `x_search`, `memory_search` และ `memory_get` | -| `owner` | เปิดเผยเครื่องมือ consult และให้ agent ปกติใช้นโยบายเครื่องมือ agent ตามปกติ | +| `safe-read-only` | เปิดเผยเครื่องมือ consult และจำกัด agent ปกติไว้ที่ `read`, `web_search`, `web_fetch`, `x_search`, `memory_search` และ `memory_get` | +| `owner` | เปิดเผยเครื่องมือ consult และให้ agent ปกติใช้นโยบายเครื่องมือ agent ปกติ | | `none` | ไม่เปิดเผยเครื่องมือ consult `realtime.tools` แบบกำหนดเองยังคงถูกส่งผ่านไปยังผู้ให้บริการเรียลไทม์ | ### ตัวอย่างผู้ให้บริการเรียลไทม์ - ค่าเริ่มต้น: คีย์ API จาก `realtime.providers.google.apiKey`, + ค่าเริ่มต้น: API key จาก `realtime.providers.google.apiKey`, `GEMINI_API_KEY` หรือ `GOOGLE_GENERATIVE_AI_API_KEY`; โมเดล `gemini-2.5-flash-native-audio-preview-12-2025`; เสียง `Kore` + `sessionResumption` และ `contextWindowCompression` เปิดโดยค่าเริ่มต้นสำหรับการโทรที่ยาวขึ้นและ + reconnect ได้ ใช้ `silenceDurationMs`, `startSensitivity` และ + `endSensitivity` เพื่อปรับการสลับตาที่เร็วขึ้นบนเสียงโทรศัพท์ ```json5 { @@ -276,6 +280,8 @@ Gateway จากนั้นรีสตาร์ท Gateway เพื่อโ apiKey: "${GEMINI_API_KEY}", model: "gemini-2.5-flash-native-audio-preview-12-2025", voice: "Kore", + silenceDurationMs: 500, + startSensitivity: "high", }, }, }, @@ -311,20 +317,20 @@ Gateway จากนั้นรีสตาร์ท Gateway เพื่อโ ดู [ผู้ให้บริการ Google](/th/providers/google) และ -[ผู้ให้บริการ OpenAI](/th/providers/openai) สำหรับตัวเลือกเสียงเรียลไทม์ +[ผู้ให้บริการ OpenAI](/th/providers/openai) สำหรับตัวเลือกเสียงแบบเรียลไทม์ เฉพาะผู้ให้บริการ ## การถอดเสียงแบบสตรีมมิง -`streaming` เลือกผู้ให้บริการถอดเสียงเรียลไทม์สำหรับเสียงสดของสายโทร +`streaming` เลือกผู้ให้บริการถอดเสียงแบบเรียลไทม์สำหรับเสียงสายสด -พฤติกรรม runtime ปัจจุบัน: +พฤติกรรมรันไทม์ปัจจุบัน: - `streaming.provider` เป็นตัวเลือกเสริม หากไม่ได้ตั้งค่า Voice Call จะใช้ผู้ให้บริการถอดเสียงแบบเรียลไทม์รายแรกที่ลงทะเบียนไว้ -- ผู้ให้บริการถอดเสียงแบบเรียลไทม์ที่มาพร้อมแพ็กเกจ: Deepgram (`deepgram`), ElevenLabs (`elevenlabs`), Mistral (`mistral`), OpenAI (`openai`) และ xAI (`xai`) ซึ่งลงทะเบียนโดย Plugin ของผู้ให้บริการแต่ละราย -- คอนฟิกดิบที่ผู้ให้บริการเป็นเจ้าของอยู่ใต้ `streaming.providers.` +- ผู้ให้บริการถอดเสียงแบบเรียลไทม์ที่รวมมาให้: Deepgram (`deepgram`), ElevenLabs (`elevenlabs`), Mistral (`mistral`), OpenAI (`openai`) และ xAI (`xai`) ซึ่งลงทะเบียนโดย Plugin ผู้ให้บริการของตน +- การกำหนดค่าดิบที่ผู้ให้บริการเป็นเจ้าของอยู่ใต้ `streaming.providers.` - หลังจาก Twilio ส่งข้อความ `start` ของสตรีมที่ยอมรับแล้ว Voice Call จะลงทะเบียนสตรีมทันที จัดคิวสื่อขาเข้าผ่านผู้ให้บริการถอดเสียงระหว่างที่ผู้ให้บริการกำลังเชื่อมต่อ และเริ่มคำทักทายแรกหลังจากการถอดเสียงแบบเรียลไทม์พร้อมแล้วเท่านั้น -- หาก `streaming.provider` ชี้ไปยังผู้ให้บริการที่ไม่ได้ลงทะเบียน หรือไม่มีผู้ให้บริการที่ลงทะเบียนไว้ Voice Call จะบันทึกคำเตือนและข้ามการสตรีมสื่อแทนที่จะทำให้ Plugin ทั้งหมดล้มเหลว +- หาก `streaming.provider` ชี้ไปยังผู้ให้บริการที่ไม่ได้ลงทะเบียน หรือไม่มีผู้ให้บริการใดลงทะเบียนไว้ Voice Call จะบันทึกคำเตือนและข้ามการสตรีมสื่อแทนที่จะทำให้ Plugin ทั้งหมดล้มเหลว ### ตัวอย่างผู้ให้บริการสตรีมมิง @@ -363,7 +369,7 @@ Gateway จากนั้นรีสตาร์ท Gateway เพื่อโ ค่าเริ่มต้น: คีย์ API `streaming.providers.xai.apiKey` หรือ `XAI_API_KEY`; - ปลายทาง `wss://api.x.ai/v1/stt`; การเข้ารหัส `mulaw`; อัตราสุ่มตัวอย่าง `8000`; + เอนด์พอยต์ `wss://api.x.ai/v1/stt`; การเข้ารหัส `mulaw`; อัตราตัวอย่าง `8000`; `endpointingMs: 800`; `interimResults: true`. ```json5 @@ -394,11 +400,11 @@ Gateway จากนั้นรีสตาร์ท Gateway เพื่อโ -## TTS สำหรับการโทร +## TTS สำหรับสายโทรศัพท์ -Voice Call ใช้คอนฟิกหลัก `messages.tts` สำหรับการสตรีม -เสียงพูดในการโทร คุณสามารถเขียนทับได้ใต้คอนฟิก Plugin ด้วย -**รูปแบบเดียวกัน** — โดยจะ deep-merge กับ `messages.tts` +Voice Call ใช้การกำหนดค่า `messages.tts` หลักสำหรับเสียงพูดแบบสตรีมมิง +ในสายโทรศัพท์ คุณสามารถแทนที่ได้ใต้การกำหนดค่า Plugin ด้วย +**รูปแบบเดียวกัน** — ระบบจะผสานเชิงลึกกับ `messages.tts` ```json5 { @@ -415,22 +421,22 @@ Voice Call ใช้คอนฟิกหลัก `messages.tts` สำหร ``` -**Microsoft speech จะถูกละเว้นสำหรับการโทรด้วยเสียง** เสียงโทรศัพท์ต้องใช้ PCM; -การขนส่งของ Microsoft ในปัจจุบันไม่เปิดเผยเอาต์พุต PCM สำหรับโทรศัพท์ +**Microsoft speech จะถูกละเว้นสำหรับสายเสียง** เสียงโทรศัพท์ต้องใช้ PCM; +ทรานสปอร์ต Microsoft ปัจจุบันไม่ได้เปิดเผยเอาต์พุต PCM สำหรับโทรศัพท์ -หมายเหตุเกี่ยวกับลักษณะการทำงาน: +หมายเหตุพฤติกรรม: -- คีย์ `tts.` แบบเดิมภายในคอนฟิก Plugin (`openai`, `elevenlabs`, `microsoft`, `edge`) จะถูกซ่อมแซมโดย `openclaw doctor --fix`; คอนฟิกที่คอมมิตควรใช้ `tts.providers.` -- ใช้ TTS หลักเมื่อเปิดใช้การสตรีมสื่อของ Twilio; มิฉะนั้นการโทรจะถอยกลับไปใช้เสียงดั้งเดิมของผู้ให้บริการ -- หากสตรีมสื่อของ Twilio กำลังทำงานอยู่ Voice Call จะไม่ถอยกลับไปใช้ TwiML `` หาก TTS สำหรับโทรศัพท์ไม่พร้อมใช้งานในสถานะนั้น คำขอเล่นเสียงจะล้มเหลวแทนที่จะผสมเส้นทางการเล่นเสียงสองแบบ -- เมื่อ TTS สำหรับโทรศัพท์ถอยกลับไปยังผู้ให้บริการรอง Voice Call จะบันทึกคำเตือนพร้อมเชนผู้ให้บริการ (`from`, `to`, `attempts`) สำหรับการดีบัก -- เมื่อ barge-in ของ Twilio หรือการรื้อสตรีมล้างคิว TTS ที่รออยู่ คำขอเล่นเสียงที่อยู่ในคิวจะสิ้นสุดสถานะแทนที่จะทำให้ผู้โทรค้างระหว่างรอการเล่นเสียงเสร็จสิ้น +- คีย์ `tts.` แบบเดิมภายในการกำหนดค่า Plugin (`openai`, `elevenlabs`, `microsoft`, `edge`) จะถูกซ่อมแซมโดย `openclaw doctor --fix`; การกำหนดค่าที่คอมมิตควรใช้ `tts.providers.` +- ใช้ TTS หลักเมื่อเปิดใช้การสตรีมสื่อ Twilio; มิฉะนั้นสายโทรศัพท์จะย้อนกลับไปใช้เสียงเนทีฟของผู้ให้บริการ +- หากสตรีมสื่อ Twilio ทำงานอยู่แล้ว Voice Call จะไม่ย้อนกลับไปใช้ TwiML `` หาก TTS สำหรับโทรศัพท์ไม่พร้อมใช้งานในสถานะนั้น คำขอเล่นเสียงจะล้มเหลวแทนที่จะผสมเส้นทางการเล่นเสียงสองแบบ +- เมื่อ TTS สำหรับโทรศัพท์ย้อนกลับไปใช้ผู้ให้บริการสำรอง Voice Call จะบันทึกคำเตือนพร้อมเชนผู้ให้บริการ (`from`, `to`, `attempts`) เพื่อการดีบัก +- เมื่อ Twilio barge-in หรือการรื้อถอนสตรีมล้างคิว TTS ที่รอดำเนินการ คำขอเล่นเสียงที่เข้าคิวไว้จะจบสถานะแทนที่จะค้างผู้โทรที่รอให้การเล่นเสียงเสร็จ ### ตัวอย่าง TTS - + ```json5 { messages: { @@ -444,7 +450,7 @@ Voice Call ใช้คอนฟิกหลัก `messages.tts` สำหร } ``` - + ```json5 { plugins: { @@ -468,7 +474,7 @@ Voice Call ใช้คอนฟิกหลัก `messages.tts` สำหร } ``` - + ```json5 { plugins: { @@ -492,9 +498,9 @@ Voice Call ใช้คอนฟิกหลัก `messages.tts` สำหร -## สายโทรเข้า +## สายขาเข้า -นโยบายขาเข้ามีค่าเริ่มต้นเป็น `disabled` หากต้องการเปิดใช้สายโทรเข้า ให้ตั้งค่า: +นโยบายขาเข้ามีค่าเริ่มต้นเป็น `disabled` หากต้องการเปิดใช้สายขาเข้า ให้ตั้งค่า: ```json5 { @@ -505,33 +511,33 @@ Voice Call ใช้คอนฟิกหลัก `messages.tts` สำหร ``` -`inboundPolicy: "allowlist"` เป็นหน้าจอกรอง caller-ID ที่มีความเชื่อมั่นต่ำ -Plugin จะทำให้ค่า `From` ที่ผู้ให้บริการส่งมาเป็นรูปแบบปกติและเปรียบเทียบกับ -`allowFrom` การตรวจสอบ Webhook ยืนยันความถูกต้องของการส่งจากผู้ให้บริการและ +`inboundPolicy: "allowlist"` เป็นการคัดกรองหมายเลขผู้โทรที่มีความน่าเชื่อต่ำ +Plugin จะทำให้ค่า `From` ที่ผู้ให้บริการส่งมาอยู่ในรูปแบบปกติและเปรียบเทียบกับ +`allowFrom` การตรวจสอบ Webhook ยืนยันการส่งจากผู้ให้บริการและ ความสมบูรณ์ของเพย์โหลด แต่ไม่ได้ **พิสูจน์** ความเป็นเจ้าของหมายเลขผู้โทร -PSTN/VoIP ให้ถือว่า `allowFrom` เป็นการกรอง caller-ID ไม่ใช่อัตลักษณ์ผู้โทร +PSTN/VoIP ให้ถือว่า `allowFrom` เป็นการกรองหมายเลขผู้โทร ไม่ใช่ตัวตนผู้โทร ที่แข็งแรง การตอบกลับอัตโนมัติใช้ระบบเอเจนต์ ปรับแต่งด้วย `responseModel`, `responseSystemPrompt` และ `responseTimeoutMs` -### การกำหนดเส้นทางแยกตามหมายเลข +### การกำหนดเส้นทางรายหมายเลข -ใช้ `numbers` เมื่อ Plugin Voice Call หนึ่งรายการรับสายสำหรับหมายเลขโทรศัพท์หลาย -หมายเลข และแต่ละหมายเลขควรทำงานเหมือนสายคนละสาย ตัวอย่างเช่น หมายเลขหนึ่ง -อาจใช้ผู้ช่วยส่วนตัวโทนเป็นกันเอง ขณะที่อีกหมายเลขหนึ่งใช้บุคลิกทางธุรกิจ +ใช้ `numbers` เมื่อ Plugin Voice Call หนึ่งรายการรับสายสำหรับหมายเลขโทรศัพท์หลายหมายเลข +และแต่ละหมายเลขควรทำงานเหมือนคนละสาย ตัวอย่างเช่น หมายเลขหนึ่ง +สามารถใช้ผู้ช่วยส่วนตัวแบบเป็นกันเอง ขณะที่อีกหมายเลขใช้บุคลิกธุรกิจ เอเจนต์ตอบกลับคนละตัว และเสียง TTS คนละเสียง -เส้นทางถูกเลือกจากหมายเลข `To` ที่ผู้ให้บริการส่งมา คีย์ต้องเป็นหมายเลข -E.164 เมื่อมีสายเข้า Voice Call จะระบุเส้นทางที่ตรงกันหนึ่งครั้ง -เก็บเส้นทางที่ตรงกันไว้ในระเบียนการโทร และนำคอนฟิกที่มีผลนั้นกลับมาใช้ซ้ำ -สำหรับคำทักทาย เส้นทางตอบกลับอัตโนมัติแบบคลาสสิก เส้นทางปรึกษาแบบเรียลไทม์ -และการเล่นเสียง TTS หากไม่มีเส้นทางใดตรงกัน จะใช้คอนฟิก Voice Call ส่วนกลาง -สายโทรออกไม่ใช้ `numbers`; ให้ส่งเป้าหมายขาออก ข้อความ และ -เซสชันอย่างชัดเจนเมื่อเริ่มการโทร +เส้นทางจะถูกเลือกจากหมายเลข `To` ที่ผู้ให้บริการส่งมา คีย์ต้องเป็น +หมายเลข E.164 เมื่อสายเข้ามา Voice Call จะระบุเส้นทางที่ตรงกันหนึ่งครั้ง +จัดเก็บเส้นทางที่ตรงกันไว้ในบันทึกสาย และนำการกำหนดค่าที่มีผลนั้นกลับมาใช้ +สำหรับคำทักทาย เส้นทางตอบกลับอัตโนมัติแบบคลาสสิก เส้นทางปรึกษาแบบเรียลไทม์ และการเล่นเสียง +TTS หากไม่มีเส้นทางใดตรงกัน จะใช้การกำหนดค่า Voice Call แบบส่วนกลาง +สายขาออกจะไม่ใช้ `numbers`; ให้ส่งเป้าหมายขาออก ข้อความ และ +เซสชันอย่างชัดเจนเมื่อเริ่มสาย -การเขียนทับเส้นทางรองรับรายการต่อไปนี้ในปัจจุบัน: +การแทนที่เส้นทางปัจจุบันรองรับ: - `inboundGreeting` - `tts` @@ -540,8 +546,8 @@ E.164 เมื่อมีสายเข้า Voice Call จะระบุ - `responseSystemPrompt` - `responseTimeoutMs` -ค่าเส้นทาง `tts` จะ deep-merge ทับคอนฟิก `tts` ส่วนกลางของ Voice Call ดังนั้น -โดยปกติคุณสามารถเขียนทับเฉพาะเสียงของผู้ให้บริการได้: +ค่าเส้นทาง `tts` จะผสานเชิงลึกทับการกำหนดค่า `tts` ของ Voice Call ส่วนกลาง ดังนั้น +โดยปกติคุณสามารถแทนที่เฉพาะเสียงของผู้ให้บริการได้: ```json5 { @@ -567,53 +573,53 @@ E.164 เมื่อมีสายเข้า Voice Call จะระบุ } ``` -### สัญญาเอาต์พุตคำพูด +### สัญญาเอาต์พุตเสียงพูด -สำหรับการตอบกลับอัตโนมัติ Voice Call จะต่อท้ายสัญญาเอาต์พุตคำพูดแบบเข้มงวดเข้ากับ -พรอมป์ระบบ: +สำหรับการตอบกลับอัตโนมัติ Voice Call จะต่อท้ายสัญญาเอาต์พุตเสียงพูดแบบเข้มงวด +เข้ากับพรอมป์ต์ระบบ: ```text {"spoken":"..."} ``` -Voice Call แยกข้อความคำพูดอย่างระมัดระวัง: +Voice Call ดึงข้อความคำพูดอย่างระมัดระวัง: -- ละเว้นเพย์โหลดที่ทำเครื่องหมายเป็นเนื้อหา reasoning/error -- แยกวิเคราะห์ JSON ตรง, JSON ใน fence หรือคีย์ `"spoken"` แบบอินไลน์ -- ถอยกลับไปใช้ข้อความธรรมดาและลบย่อหน้าเกริ่นนำที่น่าจะเป็นการวางแผน/เมตา +- ละเว้นเพย์โหลดที่ทำเครื่องหมายเป็นเนื้อหาการให้เหตุผล/ข้อผิดพลาด +- แยกวิเคราะห์ JSON โดยตรง, JSON ใน fenced block หรือคีย์ `"spoken"` แบบอินไลน์ +- ย้อนกลับไปใช้ข้อความธรรมดาและลบย่อหน้านำที่น่าจะเป็นการวางแผน/เมตา -สิ่งนี้ช่วยให้การเล่นเสียงคำพูดมุ่งเน้นที่ข้อความสำหรับผู้โทรและหลีกเลี่ยง -การรั่วไหลของข้อความวางแผนเข้าไปในเสียง +สิ่งนี้ช่วยให้การเล่นเสียงพูดเน้นข้อความสำหรับผู้โทรและหลีกเลี่ยง +การรั่วไหลข้อความวางแผนไปยังเสียง -### ลักษณะการทำงานเมื่อเริ่มการสนทนา +### พฤติกรรมการเริ่มต้นการสนทนา สำหรับสาย `conversation` ขาออก การจัดการข้อความแรกผูกกับสถานะ การเล่นเสียงสด: -- การล้างคิว barge-in และการตอบกลับอัตโนมัติจะถูกระงับเฉพาะขณะที่คำทักทายแรกกำลังพูดอยู่เท่านั้น -- หากการเล่นเสียงแรกเริ่มล้มเหลว การโทรจะกลับไปเป็น `listening` และข้อความแรกยังคงอยู่ในคิวเพื่อรอลองใหม่ -- การเล่นเสียงแรกเริ่มสำหรับการสตรีม Twilio จะเริ่มเมื่อสตรีมเชื่อมต่อโดยไม่มีดีเลย์เพิ่มเติม -- barge-in จะยกเลิกการเล่นเสียงที่กำลังทำงานและล้างรายการ TTS ของ Twilio ที่เข้าคิวแล้วแต่ยังไม่ได้เริ่มเล่น รายการที่ถูกล้างจะ resolve เป็น skipped เพื่อให้ลอจิกการตอบกลับถัดไปดำเนินต่อได้โดยไม่ต้องรอเสียงที่จะไม่มีวันเล่น -- การสนทนาเสียงแบบเรียลไทม์ใช้เทิร์นเปิดของสตรีมเรียลไทม์เอง Voice Call **จะไม่** โพสต์อัปเดต TwiML `` แบบเดิมสำหรับข้อความแรกเริ่มนั้น ดังนั้นเซสชัน `` ขาออกจะยังคงแนบอยู่ +- การล้างคิวจาก barge-in และการตอบกลับอัตโนมัติจะถูกระงับเฉพาะขณะที่คำทักทายแรกกำลังพูดอยู่ +- หากการเล่นเสียงแรกเริ่มล้มเหลว สายจะกลับไปเป็น `listening` และข้อความแรกจะยังคงอยู่ในคิวเพื่อรอลองใหม่ +- การเล่นเสียงแรกเริ่มสำหรับการสตรีม Twilio จะเริ่มเมื่อสตรีมเชื่อมต่อโดยไม่มีความล่าช้าเพิ่มเติม +- Barge-in ยกเลิกการเล่นเสียงที่ทำงานอยู่และล้างรายการ Twilio TTS ที่เข้าคิวไว้แต่ยังไม่ได้เล่น รายการที่ถูกล้างจะ resolve เป็นถูกข้าม เพื่อให้ตรรกะการตอบกลับต่อเนื่องดำเนินต่อได้โดยไม่ต้องรอเสียงที่ไม่มีวันเล่น +- การสนทนาเสียงแบบเรียลไทม์ใช้เทิร์นเปิดของสตรีมเรียลไทม์เอง Voice Call จะ **ไม่** โพสต์อัปเดต TwiML `` แบบเดิมสำหรับข้อความแรกเริ่มนั้น ดังนั้นเซสชัน `` ขาออกจึงยังคงเชื่อมต่ออยู่ -### ระยะผ่อนผันเมื่อสตรีม Twilio ตัดการเชื่อมต่อ +### ช่วงผ่อนผันเมื่อสตรีม Twilio ตัดการเชื่อมต่อ -เมื่อสตรีมสื่อของ Twilio ตัดการเชื่อมต่อ Voice Call จะรอ **2000 ms** ก่อน -จบการโทรโดยอัตโนมัติ: +เมื่อสตรีมสื่อ Twilio ตัดการเชื่อมต่อ Voice Call จะรอ **2000 ms** ก่อน +สิ้นสุดสายโดยอัตโนมัติ: -- หากสตรีมเชื่อมต่อใหม่ในช่วงเวลานั้น การจบอัตโนมัติจะถูกยกเลิก -- หากไม่มีสตรีมลงทะเบียนใหม่หลังระยะผ่อนผัน การโทรจะถูกจบเพื่อป้องกันสายที่ค้างอยู่ในสถานะแอคทีฟ +- หากสตรีมเชื่อมต่อกลับในช่วงเวลานั้น การสิ้นสุดอัตโนมัติจะถูกยกเลิก +- หากไม่มีสตรีมลงทะเบียนใหม่หลังช่วงผ่อนผัน สายจะถูกสิ้นสุดเพื่อป้องกันสายที่ยัง active ค้างอยู่ ## ตัวเก็บกวาดสายค้าง -ใช้ `staleCallReaperSeconds` เพื่อจบสายที่ไม่เคยได้รับ Webhook ปลายทาง -(ตัวอย่างเช่น สายโหมดแจ้งเตือนที่ไม่เคยเสร็จสมบูรณ์) ค่าเริ่มต้น +ใช้ `staleCallReaperSeconds` เพื่อสิ้นสุดสายที่ไม่เคยได้รับ Webhook +ปลายทาง (ตัวอย่างเช่น สายโหมดแจ้งเตือนที่ไม่เคยเสร็จสมบูรณ์) ค่าเริ่มต้น คือ `0` (ปิดใช้งาน) -ช่วงที่แนะนำ: +ช่วงค่าที่แนะนำ: - **โปรดักชัน:** `120`–`300` วินาทีสำหรับโฟลว์แบบแจ้งเตือน -- ตั้งค่านี้ให้ **สูงกว่า `maxDurationSeconds`** เพื่อให้สายปกติสามารถเสร็จสิ้นได้ จุดเริ่มต้นที่ดีคือ `maxDurationSeconds + 30–60` วินาที +- ให้ค่านี้ **สูงกว่า `maxDurationSeconds`** เพื่อให้สายปกติจบได้ จุดเริ่มต้นที่ดีคือ `maxDurationSeconds + 30–60` วินาที ```json5 { @@ -632,26 +638,26 @@ Voice Call แยกข้อความคำพูดอย่างระม ## ความปลอดภัยของ Webhook -เมื่อมีพร็อกซีหรือทันเนลอยู่หน้า Gateway Plugin จะ -สร้าง URL สาธารณะขึ้นใหม่เพื่อการตรวจสอบลายเซ็น ตัวเลือกเหล่านี้ -ควบคุมว่าจะเชื่อถือส่วนหัวที่ส่งต่อใด: +เมื่อพร็อกซีหรือทันเนลอยู่หน้า Gateway Plugin จะ +สร้าง URL สาธารณะใหม่สำหรับการตรวจสอบลายเซ็น ตัวเลือกเหล่านี้ +ควบคุมว่าเฮดเดอร์ที่ส่งต่อใดเชื่อถือได้: - โฮสต์ allowlist จากส่วนหัวการส่งต่อ + อนุญาตโฮสต์จากเฮดเดอร์การส่งต่อ - เชื่อถือส่วนหัวที่ส่งต่อโดยไม่มี allowlist + เชื่อถือเฮดเดอร์ที่ส่งต่อโดยไม่ต้องมี allowlist - เชื่อถือส่วนหัวที่ส่งต่อเฉพาะเมื่อ IP ระยะไกลของคำขอตรงกับรายการ + เชื่อถือเฮดเดอร์ที่ส่งต่อเฉพาะเมื่อ IP ระยะไกลของคำขอตรงกับรายการ การป้องกันเพิ่มเติม: -- เปิดใช้ **การป้องกันการเล่นซ้ำ** ของ Webhook สำหรับ Twilio และ Plivo คำขอ Webhook ที่ถูกต้องแต่เล่นซ้ำจะได้รับการตอบรับแต่ถูกข้ามสำหรับผลข้างเคียง -- เทิร์นการสนทนาของ Twilio มีโทเค็นต่อเทิร์นในคอลแบ็ก `` ดังนั้นคอลแบ็กคำพูดที่ค้าง/เล่นซ้ำจึงไม่สามารถตอบสนองเทิร์นถอดเสียงที่รออยู่ใหม่กว่าได้ -- คำขอ Webhook ที่ไม่ได้ยืนยันตัวตนจะถูกปฏิเสธก่อนอ่านบอดี้เมื่อส่วนหัวลายเซ็นที่ผู้ให้บริการกำหนดขาดหายไป -- Webhook ของ voice-call ใช้โปรไฟล์บอดี้ก่อนยืนยันตัวตนร่วมกัน (64 KB / 5 วินาที) พร้อมขีดจำกัด in-flight ต่อ IP ก่อนตรวจสอบลายเซ็น +- เปิดใช้ **การป้องกันการเล่นซ้ำ** ของ Webhook สำหรับ Twilio และ Plivo คำขอ Webhook ที่ถูกต้องซึ่งถูกเล่นซ้ำจะได้รับการยืนยัน แต่จะข้ามผลข้างเคียง +- เทิร์นการสนทนา Twilio มีโทเค็นต่อเทิร์นในคอลแบ็ก `` ดังนั้นคอลแบ็กคำพูดที่เก่า/ถูกเล่นซ้ำจึงไม่สามารถทำให้เทิร์นทรานสคริปต์ที่รอดำเนินการใหม่กว่าสำเร็จได้ +- คำขอ Webhook ที่ไม่ได้ยืนยันตัวตนจะถูกปฏิเสธก่อนอ่าน body เมื่อเฮดเดอร์ลายเซ็นที่ผู้ให้บริการต้องการขาดหายไป +- Webhook ของ voice-call ใช้โปรไฟล์ body ก่อนยืนยันตัวตนร่วมกัน (64 KB / 5 วินาที) รวมกับขีดจำกัด in-flight ต่อ IP ก่อนการตรวจสอบลายเซ็น ตัวอย่างพร้อมโฮสต์สาธารณะที่เสถียร: @@ -687,21 +693,21 @@ openclaw voicecall latency # summarize turn latency from lo openclaw voicecall expose --mode funnel ``` -เมื่อ Gateway กำลังทำงานอยู่แล้ว คำสั่ง `voicecall` เชิงปฏิบัติการจะมอบหมาย -ไปยัง runtime ของ voice-call ที่ Gateway เป็นเจ้าของ เพื่อให้ CLI ไม่ bind -เซิร์ฟเวอร์ Webhook ตัวที่สอง หากติดต่อ Gateway ไม่ได้ คำสั่งจะถอยกลับไปใช้ -runtime ของ CLI แบบสแตนด์อโลน +เมื่อ Gateway ทำงานอยู่แล้ว คำสั่ง `voicecall` เชิงปฏิบัติการจะมอบหมายงาน +ให้รันไทม์การโทรเสียงที่ Gateway เป็นเจ้าของ เพื่อให้ CLI ไม่ผูกกับเซิร์ฟเวอร์ +webhook ตัวที่สอง หากติดต่อ Gateway ไม่ได้ คำสั่งจะถอยกลับไปใช้รันไทม์ +CLI แบบสแตนด์อโลน -`latency` อ่าน `calls.jsonl` จากพาธพื้นที่จัดเก็บ voice-call เริ่มต้น -ใช้ `--file ` เพื่อชี้ไปยังล็อกอื่น และ `--last ` เพื่อจำกัด -การวิเคราะห์ไว้ที่ระเบียน N รายการล่าสุด (ค่าเริ่มต้น 200) เอาต์พุตมี p50/p90/p99 -สำหรับเวลาแฝงของเทิร์นและเวลารอฟัง +`latency` อ่าน `calls.jsonl` จากพาธจัดเก็บการโทรเสียงเริ่มต้น +ใช้ `--file ` เพื่อชี้ไปยังบันทึกอื่น และ `--last ` เพื่อจำกัด +การวิเคราะห์ไว้ที่ N ระเบียนล่าสุด (ค่าเริ่มต้น 200) เอาต์พุตมี p50/p90/p99 +สำหรับเวลาแฝงของรอบสนทนาและเวลารอฟัง -## เครื่องมือเอเจนต์ +## เครื่องมือ Agent ชื่อเครื่องมือ: `voice_call`. -| การกระทำ | อาร์กิวเมนต์ | +| การกระทำ | อาร์กิวเมนต์ | | --------------- | ------------------------------------------ | | `initiate_call` | `message`, `to?`, `mode?`, `dtmfSequence?` | | `continue_call` | `callId`, `message` | @@ -710,11 +716,11 @@ runtime ของ CLI แบบสแตนด์อโลน | `end_call` | `callId` | | `get_status` | `callId` | -รีโพนี้มาพร้อมเอกสารทักษะที่ตรงกันที่ `skills/voice-call/SKILL.md`. +repo นี้มาพร้อมเอกสาร skill ที่ตรงกันที่ `skills/voice-call/SKILL.md`. -## RPC ของ Gateway +## Gateway RPC -| เมธอด | อาร์กิวเมนต์ | +| เมธอด | อาร์กิวเมนต์ | | -------------------- | ------------------------------------------ | | `voicecall.initiate` | `to?`, `message`, `mode?`, `dtmfSequence?` | | `voicecall.continue` | `callId`, `message` | @@ -723,32 +729,32 @@ runtime ของ CLI แบบสแตนด์อโลน | `voicecall.end` | `callId` | | `voicecall.status` | `callId` | -`dtmfSequence` ใช้ได้เฉพาะกับ `mode: "conversation"` เท่านั้น การโทรในโหมดแจ้งเตือน -ควรใช้ `voicecall.dtmf` หลังจากมีสายแล้ว หากต้องใช้ตัวเลขหลังเชื่อมต่อ +`dtmfSequence` ใช้ได้เฉพาะกับ `mode: "conversation"` เท่านั้น การโทรในโหมด +notify ควรใช้ `voicecall.dtmf` หลังจากมีการโทรแล้ว หากต้องใช้ตัวเลขหลังเชื่อมต่อ ## การแก้ไขปัญหา -### การตั้งค่าล้มเหลวจากการเปิดเผย Webhook +### การตั้งค่าล้มเหลวที่การเปิดเผย webhook -เรียกใช้การตั้งค่าจากสภาพแวดล้อมเดียวกับที่รัน Gateway: +เรียกใช้การตั้งค่าจากสภาพแวดล้อมเดียวกับที่เรียกใช้ Gateway: ```bash openclaw voicecall setup openclaw voicecall setup --json ``` -สำหรับ `twilio`, `telnyx` และ `plivo`, `webhook-exposure` ต้องเป็นสีเขียว -`publicUrl` ที่กำหนดค่าไว้ยังล้มเหลวได้เมื่อชี้ไปยังพื้นที่เครือข่ายภายในเครื่องหรือส่วนตัว -เพราะผู้ให้บริการโทรศัพท์ไม่สามารถเรียกกลับมายังที่อยู่เหล่านั้นได้ อย่าใช้ -`localhost`, `127.0.0.1`, `0.0.0.0`, `10.x`, `172.16.x`-`172.31.x`, +สำหรับ `twilio`, `telnyx` และ `plivo` นั้น `webhook-exposure` ต้องเป็นสีเขียว +`publicUrl` ที่กำหนดค่าไว้ยังคงล้มเหลวได้เมื่อชี้ไปยังพื้นที่เครือข่าย local +หรือ private เพราะผู้ให้บริการเครือข่ายโทรศัพท์ไม่สามารถเรียกกลับไปยังที่อยู่เหล่านั้นได้ +อย่าใช้ `localhost`, `127.0.0.1`, `0.0.0.0`, `10.x`, `172.16.x`-`172.31.x`, `192.168.x`, `169.254.x`, `fc00::/7` หรือ `fd00::/8` เป็น `publicUrl`. -สายออกในโหมดแจ้งเตือนของ Twilio ส่ง TwiML `` เริ่มต้นโดยตรงใน -คำขอสร้างสาย ดังนั้นข้อความพูดแรกจึงไม่ขึ้นกับการที่ Twilio ดึง TwiML จาก Webhook -ยังคงต้องมี Webhook สาธารณะสำหรับคอลแบ็กสถานะ, การโทรแบบสนทนา, DTMF ก่อนเชื่อมต่อ, -สตรีมเรียลไทม์ และการควบคุมสายหลังเชื่อมต่อ +การโทรออกของ Twilio ในโหมด notify จะส่ง TwiML `` เริ่มต้นโดยตรงใน +คำขอ create-call ดังนั้นข้อความพูดแรกจึงไม่ขึ้นกับการที่ Twilio ดึง webhook TwiML +ยังคงต้องใช้ webhook สาธารณะสำหรับ status callbacks, การโทรแบบสนทนา, +DTMF ก่อนเชื่อมต่อ, สตรีมแบบ realtime และการควบคุมสายหลังเชื่อมต่อ -ใช้พาธเปิดเผยสาธารณะหนึ่งรายการ: +ใช้พาธเปิดเผยสาธารณะหนึ่งแบบ: ```json5 { @@ -768,18 +774,18 @@ openclaw voicecall setup --json } ``` -หลังเปลี่ยนการกำหนดค่า ให้รีสตาร์ตหรือโหลด Gateway ใหม่ แล้วเรียกใช้: +หลังจากเปลี่ยน config แล้ว ให้รีสตาร์ตหรือโหลด Gateway ใหม่ จากนั้นเรียกใช้: ```bash openclaw voicecall setup openclaw voicecall smoke ``` -`voicecall smoke` เป็นการทดสอบแบบไม่ส่งผลจริง เว้นแต่คุณจะส่ง `--yes`. +`voicecall smoke` เป็นการรันแบบ dry run เว้นแต่คุณจะส่ง `--yes`. -### ข้อมูลรับรองของผู้ให้บริการล้มเหลว +### ข้อมูลรับรองผู้ให้บริการล้มเหลว -ตรวจสอบผู้ให้บริการที่เลือกและฟิลด์ข้อมูลรับรองที่ต้องใช้: +ตรวจสอบผู้ให้บริการที่เลือกและฟิลด์ข้อมูลรับรองที่จำเป็น: - Twilio: `twilio.accountSid`, `twilio.authToken` และ `fromNumber` หรือ `TWILIO_ACCOUNT_SID`, `TWILIO_AUTH_TOKEN` และ `TWILIO_FROM_NUMBER`. @@ -787,13 +793,12 @@ openclaw voicecall smoke `fromNumber`. - Plivo: `plivo.authId`, `plivo.authToken` และ `fromNumber`. -ข้อมูลรับรองต้องมีอยู่บนโฮสต์ Gateway การแก้ไขโปรไฟล์เชลล์ภายในเครื่อง -จะไม่มีผลกับ Gateway ที่กำลังรันอยู่จนกว่าจะรีสตาร์ตหรือโหลด -สภาพแวดล้อมใหม่ +ข้อมูลรับรองต้องมีอยู่บนโฮสต์ Gateway การแก้ไขโปรไฟล์ shell ในเครื่อง +จะไม่ส่งผลต่อ Gateway ที่กำลังทำงานอยู่จนกว่าจะรีสตาร์ตหรือโหลดสภาพแวดล้อมใหม่ -### สายเริ่มต้นได้แต่ Webhook ของผู้ให้บริการไม่มาถึง +### การโทรเริ่มต้นได้ แต่ webhook ของผู้ให้บริการไม่มาถึง -ยืนยันว่าคอนโซลของผู้ให้บริการชี้ไปยัง URL Webhook สาธารณะที่ถูกต้องทุกอักขระ: +ยืนยันว่าคอนโซลของผู้ให้บริการชี้ไปยัง URL webhook สาธารณะที่ถูกต้องพอดี: ```text https://voice.example.com/voice/webhook @@ -807,84 +812,84 @@ openclaw voicecall tail openclaw logs --follow ``` -สาเหตุทั่วไป: +สาเหตุที่พบบ่อย: - `publicUrl` ชี้ไปยังพาธที่ต่างจาก `serve.path`. -- URL ทันเนลเปลี่ยนหลังจาก Gateway เริ่มทำงานแล้ว -- พร็อกซีส่งต่อคำขอแต่ตัดหรือเขียนส่วนหัว host/proto ใหม่ -- ไฟร์วอลล์หรือ DNS ส่งชื่อโฮสต์สาธารณะไปยังที่อื่นที่ไม่ใช่ Gateway -- Gateway ถูกรีสตาร์ตโดยไม่ได้เปิดใช้งาน Plugin Voice Call +- URL tunnel เปลี่ยนหลังจาก Gateway เริ่มทำงาน +- proxy ส่งต่อคำขอ แต่ตัดหรือเขียน host/proto headers ใหม่ +- firewall หรือ DNS นำชื่อโฮสต์สาธารณะไปยังตำแหน่งอื่นที่ไม่ใช่ Gateway +- Gateway ถูกรีสตาร์ตโดยไม่ได้เปิดใช้งาน Voice Call Plugin -เมื่อมี reverse proxy หรือทันเนลอยู่หน้า Gateway ให้ตั้งค่า +เมื่อมี reverse proxy หรือ tunnel อยู่หน้า Gateway ให้ตั้งค่า `webhookSecurity.allowedHosts` เป็นชื่อโฮสต์สาธารณะ หรือใช้ -`webhookSecurity.trustedProxyIPs` สำหรับที่อยู่พร็อกซีที่รู้จัก ใช้ -`webhookSecurity.trustForwardingHeaders` เฉพาะเมื่อขอบเขตพร็อกซีอยู่ภายใต้ +`webhookSecurity.trustedProxyIPs` สำหรับที่อยู่ proxy ที่ทราบแน่ชัด ใช้ +`webhookSecurity.trustForwardingHeaders` เฉพาะเมื่อขอบเขต proxy อยู่ภายใต้ การควบคุมของคุณ -### การยืนยันลายเซ็นล้มเหลว +### การตรวจสอบลายเซ็นล้มเหลว -ลายเซ็นของผู้ให้บริการจะถูกตรวจสอบกับ URL สาธารณะที่ OpenClaw สร้างขึ้นใหม่ +ลายเซ็นของผู้ให้บริการจะถูกตรวจสอบเทียบกับ URL สาธารณะที่ OpenClaw สร้างใหม่ จากคำขอขาเข้า หากลายเซ็นล้มเหลว: -- ยืนยันว่า URL Webhook ของผู้ให้บริการตรงกับ `publicUrl` ทุกอักขระ รวมถึง +- ยืนยันว่า URL webhook ของผู้ให้บริการตรงกับ `publicUrl` ทุกประการ รวมถึง scheme, host และ path. -- สำหรับ URL ระดับฟรีของ ngrok ให้อัปเดต `publicUrl` เมื่อชื่อโฮสต์ของทันเนลเปลี่ยน -- ตรวจสอบว่าพร็อกซีคงส่วนหัว host และ proto เดิมไว้ หรือกำหนดค่า +- สำหรับ URL ของ ngrok free-tier ให้อัปเดต `publicUrl` เมื่อชื่อโฮสต์ tunnel เปลี่ยน +- ตรวจสอบให้แน่ใจว่า proxy รักษา host และ proto headers เดิมไว้ หรือกำหนดค่า `webhookSecurity.allowedHosts`. -- อย่าเปิดใช้ `skipSignatureVerification` นอกการทดสอบภายในเครื่อง +- อย่าเปิดใช้ `skipSignatureVerification` นอกการทดสอบ local -### การเข้าร่วม Google Meet ผ่าน Twilio ล้มเหลว +### การเข้าร่วม Google Meet ด้วย Twilio ล้มเหลว -Google Meet ใช้ Plugin นี้สำหรับการเข้าร่วมแบบโทรเข้า Twilio ก่อนอื่นให้ตรวจสอบ Voice Call: +Google Meet ใช้ Plugin นี้สำหรับการเข้าร่วมแบบ dial-in ผ่าน Twilio ก่อนอื่นให้ตรวจสอบ Voice Call: ```bash openclaw voicecall setup openclaw voicecall smoke --to "+15555550123" ``` -จากนั้นตรวจสอบทรานสปอร์ต Google Meet โดยตรง: +จากนั้นตรวจสอบการขนส่งของ Google Meet อย่างชัดเจน: ```bash openclaw googlemeet setup --transport twilio ``` -หาก Voice Call เป็นสีเขียวแต่ผู้เข้าร่วม Meet ไม่เคยเข้าร่วม ให้ตรวจสอบ -หมายเลขโทรเข้า Meet, PIN และ `--dtmf-sequence` สายโทรศัพท์อาจปกติดีในขณะที่ -การประชุมปฏิเสธหรือไม่สนใจลำดับ DTMF ที่ไม่ถูกต้อง +หาก Voice Call เป็นสีเขียวแต่ผู้เข้าร่วม Meet ไม่เคยเข้าร่วม ให้ตรวจสอบหมายเลข +dial-in ของ Meet, PIN และ `--dtmf-sequence` สายโทรศัพท์อาจปกติดีแม้การประชุม +จะปฏิเสธหรือเพิกเฉยต่อลำดับ DTMF ที่ไม่ถูกต้อง Google Meet ส่งลำดับ DTMF ของ Meet และข้อความแนะนำไปยัง `voicecall.start`. -สำหรับสาย Twilio, Voice Call จะให้บริการ TwiML ของ DTMF ก่อน เปลี่ยนเส้นทางกลับไปยัง -Webhook แล้วเปิดสตรีมสื่อเรียลไทม์เพื่อให้สร้างข้อความแนะนำที่บันทึกไว้ +สำหรับการโทร Twilio นั้น Voice Call จะให้บริการ DTMF TwiML ก่อน เปลี่ยนเส้นทางกลับไปยัง +webhook แล้วจึงเปิดสตรีมสื่อแบบ realtime เพื่อให้ข้อความแนะนำที่บันทึกไว้ถูกสร้าง หลังจากผู้เข้าร่วมทางโทรศัพท์เข้าร่วมการประชุมแล้ว -ใช้ `openclaw logs --follow` สำหรับร่องรอยระยะสด การเข้าร่วม Twilio Meet -ที่ปกติจะบันทึกลำดับนี้: +ใช้ `openclaw logs --follow` สำหรับ trace ช่วง live การเข้าร่วม Twilio Meet +ที่ทำงานปกติจะบันทึกลำดับนี้: - Google Meet มอบหมายการเข้าร่วม Twilio ให้ Voice Call -- Voice Call จัดเก็บ TwiML ของ DTMF ก่อนเชื่อมต่อ -- TwiML เริ่มต้นของ Twilio ถูกใช้งานและให้บริการก่อนการจัดการเรียลไทม์ -- Voice Call ให้บริการ TwiML เรียลไทม์สำหรับสาย Twilio -- บริดจ์เรียลไทม์เริ่มต้นพร้อมคำทักทายเริ่มต้นที่ถูกเข้าคิวไว้ +- Voice Call จัดเก็บ DTMF TwiML ก่อนเชื่อมต่อ +- Twilio initial TwiML ถูกใช้และให้บริการก่อนการจัดการแบบ realtime +- Voice Call ให้บริการ realtime TwiML สำหรับการโทร Twilio +- realtime bridge เริ่มต้นพร้อมคำทักทายเริ่มต้นที่เข้าคิวไว้ -`openclaw voicecall tail` ยังคงแสดงระเบียนสายที่คงอยู่ ซึ่งมีประโยชน์สำหรับ -สถานะสายและทรานสคริปต์ แต่ไม่ใช่ทุกการเปลี่ยนผ่านของ Webhook/เรียลไทม์จะปรากฏ -ที่นั่น +`openclaw voicecall tail` ยังคงแสดงระเบียนการโทรที่บันทึกถาวร มีประโยชน์สำหรับ +สถานะการโทรและทรานสคริปต์ แต่ไม่ใช่ทุกการเปลี่ยนผ่านของ webhook/realtime +ที่จะปรากฏที่นั่น -### สายเรียลไทม์ไม่มีเสียงพูด +### การโทรแบบ realtime ไม่มีเสียงพูด -ยืนยันว่าเปิดใช้โหมดเสียงเพียงโหมดเดียว `realtime.enabled` และ +ยืนยันว่าเปิดใช้งานโหมดเสียงเพียงโหมดเดียว `realtime.enabled` และ `streaming.enabled` ไม่สามารถเป็น true พร้อมกันได้ -สำหรับสาย Twilio แบบเรียลไทม์ ให้ตรวจสอบเพิ่มเติมว่า: +สำหรับการโทร Twilio แบบ realtime ให้ตรวจสอบเพิ่มเติมว่า: -- มีการโหลดและลงทะเบียน Plugin ผู้ให้บริการเรียลไทม์แล้ว +- Plugin ผู้ให้บริการ realtime ถูกโหลดและลงทะเบียนแล้ว - `realtime.provider` ไม่ได้ตั้งค่าไว้ หรือระบุชื่อผู้ให้บริการที่ลงทะเบียนแล้ว -- คีย์ API ของผู้ให้บริการพร้อมใช้งานสำหรับกระบวนการ Gateway -- `openclaw logs --follow` แสดงว่าให้บริการ TwiML เรียลไทม์แล้ว บริดจ์เรียลไทม์ - เริ่มต้นแล้ว และคำทักทายเริ่มต้นถูกเข้าคิวแล้ว +- API key ของผู้ให้บริการพร้อมใช้งานสำหรับ process ของ Gateway +- `openclaw logs --follow` แสดงว่า realtime TwiML ถูกให้บริการ, realtime bridge + เริ่มต้นแล้ว และคำทักทายเริ่มต้นถูกเข้าคิวไว้ ## ที่เกี่ยวข้อง - [โหมดพูดคุย](/th/nodes/talk) - [ข้อความเป็นเสียงพูด](/th/tools/tts) -- [การปลุกด้วยเสียง](/th/nodes/voicewake) +- [ปลุกด้วยเสียง](/th/nodes/voicewake) diff --git a/docs/th/providers/elevenlabs.md b/docs/th/providers/elevenlabs.md index b4437494f..597fa58cb 100644 --- a/docs/th/providers/elevenlabs.md +++ b/docs/th/providers/elevenlabs.md @@ -1,32 +1,32 @@ --- read_when: - - คุณต้องการใช้ระบบแปลงข้อความเป็นเสียงของ ElevenLabs ใน OpenClaw - - คุณต้องการใช้ระบบแปลงเสียงเป็นข้อความ ElevenLabs Scribe สำหรับไฟล์แนบเสียง - - คุณต้องการใช้การถอดเสียงแบบเรียลไทม์ของ ElevenLabs สำหรับ Voice Call -summary: ใช้เสียงพูด ElevenLabs, Scribe STT และการถอดเสียงแบบเรียลไทม์กับ OpenClaw + - คุณต้องการใช้การแปลงข้อความเป็นเสียงของ ElevenLabs ใน OpenClaw + - คุณต้องการใช้ ElevenLabs Scribe สำหรับการถอดเสียงพูดเป็นข้อความจากไฟล์แนบเสียง + - คุณต้องการการถอดเสียงแบบเรียลไทม์ด้วย ElevenLabs สำหรับการโทรด้วยเสียงหรือ Google Meet +summary: ใช้เสียงพูดของ ElevenLabs, Scribe STT และการถอดเสียงแบบเรียลไทม์กับ OpenClaw title: ElevenLabs x-i18n: - generated_at: "2026-04-25T13:57:04Z" - model: gpt-5.4 + generated_at: "2026-05-04T07:06:18Z" + model: gpt-5.5 provider: openai - source_hash: 1f858a344228c6355cd5fdc3775cddac39e0075f2e9fcf7683271f11be03a31a + source_hash: 4c880bf9dcab01ef70779c74576c70ea5d0203b96b5f739291842fafcb4bdb4b source_path: providers/elevenlabs.md - workflow: 15 + workflow: 16 --- OpenClaw ใช้ ElevenLabs สำหรับการแปลงข้อความเป็นเสียง, การแปลงเสียงเป็นข้อความแบบแบตช์ด้วย Scribe -v2 และ STT แบบสตรีมมิงสำหรับ Voice Call ด้วย Scribe v2 Realtime +v2 และ STT แบบสตรีมด้วย Scribe v2 Realtime. -| ความสามารถ | พื้นที่ใช้งานใน OpenClaw | ค่าเริ่มต้น | -| ----------------------- | ----------------------------------------------- | ------------------------- | -| การแปลงข้อความเป็นเสียง | `messages.tts` / `talk` | `eleven_multilingual_v2` | -| การแปลงเสียงเป็นข้อความแบบแบตช์ | `tools.media.audio` | `scribe_v2` | -| การแปลงเสียงเป็นข้อความแบบสตรีมมิง | Voice Call `streaming.provider: "elevenlabs"` | `scribe_v2_realtime` | +| ความสามารถ | พื้นผิวของ OpenClaw | ค่าเริ่มต้น | +| ------------------------ | -------------------------------------------------------------------- | ------------------------ | +| การแปลงข้อความเป็นเสียง | `messages.tts` / `talk` | `eleven_multilingual_v2` | +| การแปลงเสียงเป็นข้อความแบบแบตช์ | `tools.media.audio` | `scribe_v2` | +| การแปลงเสียงเป็นข้อความแบบสตรีม | การสตรีม Voice Call หรือ Google Meet `realtime.transcriptionProvider` | `scribe_v2_realtime` | ## การยืนยันตัวตน -ตั้งค่า `ELEVENLABS_API_KEY` ใน environment โดย `XI_API_KEY` ก็รองรับเช่นกัน -เพื่อความเข้ากันได้กับเครื่องมือ ElevenLabs ที่มีอยู่เดิม +ตั้งค่า `ELEVENLABS_API_KEY` ในสภาพแวดล้อม ระบบยังยอมรับ `XI_API_KEY` เพื่อ +ความเข้ากันได้กับเครื่องมือ ElevenLabs ที่มีอยู่. ```bash export ELEVENLABS_API_KEY="..." @@ -50,12 +50,12 @@ export ELEVENLABS_API_KEY="..." } ``` -ตั้งค่า `modelId` เป็น `eleven_v3` เพื่อใช้ ElevenLabs v3 TTS โดย OpenClaw ยังคงใช้ -`eleven_multilingual_v2` เป็นค่าเริ่มต้นสำหรับการติดตั้งเดิม +ตั้งค่า `modelId` เป็น `eleven_v3` เพื่อใช้ ElevenLabs v3 TTS. OpenClaw ยังคงใช้ +`eleven_multilingual_v2` เป็นค่าเริ่มต้นสำหรับการติดตั้งที่มีอยู่. ## การแปลงเสียงเป็นข้อความ -ใช้ Scribe v2 สำหรับไฟล์แนบเสียงขาเข้าและเสียงพูดที่บันทึกไว้ช่วงสั้น ๆ: +ใช้ Scribe v2 สำหรับไฟล์แนบเสียงขาเข้าและช่วงเสียงพูดที่บันทึกไว้แบบสั้น: ```json5 { @@ -71,20 +71,21 @@ export ELEVENLABS_API_KEY="..." ``` OpenClaw ส่งเสียงแบบ multipart ไปยัง ElevenLabs `/v1/speech-to-text` พร้อม -`model_id: "scribe_v2"` โดยคำใบ้ภาษาจะถูกแมปไปยัง `language_code` เมื่อมีการระบุ +`model_id: "scribe_v2"`. คำใบ้ภาษาจะแมปไปยัง `language_code` เมื่อมีอยู่. -## STT แบบสตรีมมิงสำหรับ Voice Call +## STT แบบสตรีม -Plugin `elevenlabs` ที่มีมาในตัวจะลงทะเบียน Scribe v2 Realtime สำหรับการถอดเสียงแบบสตรีมมิงของ Voice Call +Plugin `elevenlabs` ที่รวมมาให้จะลงทะเบียน Scribe v2 Realtime สำหรับ Voice Call และ +การถอดความแบบสตรีมในโหมดเอเจนต์ของ Google Meet. -| การตั้งค่า | เส้นทาง config | ค่าเริ่มต้น | -| ---------------- | ------------------------------------------------------------------------- | -------------------------------------------------- | -| API key | `plugins.entries.voice-call.config.streaming.providers.elevenlabs.apiKey` | ใช้ `ELEVENLABS_API_KEY` / `XI_API_KEY` เป็นค่า fallback | -| โมเดล | `...elevenlabs.modelId` | `scribe_v2_realtime` | -| รูปแบบเสียง | `...elevenlabs.audioFormat` | `ulaw_8000` | -| อัตราการสุ่มตัวอย่าง | `...elevenlabs.sampleRate` | `8000` | -| กลยุทธ์การ commit | `...elevenlabs.commitStrategy` | `vad` | -| ภาษา | `...elevenlabs.languageCode` | (ไม่ตั้งค่า) | +| การตั้งค่า | เส้นทางการกำหนดค่า | ค่าเริ่มต้น | +| --------------- | ------------------------------------------------------------------------- | ------------------------------------------------- | +| คีย์ API | `plugins.entries.voice-call.config.streaming.providers.elevenlabs.apiKey` | ย้อนกลับไปใช้ `ELEVENLABS_API_KEY` / `XI_API_KEY` | +| โมเดล | `...elevenlabs.modelId` | `scribe_v2_realtime` | +| รูปแบบเสียง | `...elevenlabs.audioFormat` | `ulaw_8000` | +| อัตราสุ่มตัวอย่าง | `...elevenlabs.sampleRate` | `8000` | +| กลยุทธ์ commit | `...elevenlabs.commitStrategy` | `vad` | +| ภาษา | `...elevenlabs.languageCode` | (ไม่ได้ตั้งค่า) | ```json5 { @@ -112,12 +113,18 @@ Plugin `elevenlabs` ที่มีมาในตัวจะลงทะเบ ``` -Voice Call รับสื่อจาก Twilio เป็น G.711 u-law ที่ 8 kHz โดย provider แบบเรียลไทม์ของ ElevenLabs -ใช้ค่าเริ่มต้นเป็น `ulaw_8000` ดังนั้นเฟรมโทรศัพท์จึงสามารถส่งต่อได้โดยไม่ต้อง -transcode +Voice Call รับสื่อ Twilio เป็น G.711 u-law ที่ 8 kHz. Provider แบบ realtime ของ ElevenLabs +มีค่าเริ่มต้นเป็น `ulaw_8000` ดังนั้นเฟรมโทรศัพท์จึงสามารถส่งต่อได้โดยไม่ต้อง +แปลงรหัส. +สำหรับโหมดเอเจนต์ของ Google Meet ให้ตั้งค่า +`plugins.entries.google-meet.config.realtime.transcriptionProvider` เป็น +`"elevenlabs"` และกำหนดค่าบล็อก Provider เดียวกันภายใต้ +`plugins.entries.google-meet.config.realtime.providers.elevenlabs`. + ## ที่เกี่ยวข้อง - [การแปลงข้อความเป็นเสียง](/th/tools/tts) +- [Google Meet](/th/plugins/google-meet) - [การเลือกโมเดล](/th/concepts/model-providers) diff --git a/docs/th/providers/google.md b/docs/th/providers/google.md index ef084c0f7..9ff1b3f55 100644 --- a/docs/th/providers/google.md +++ b/docs/th/providers/google.md @@ -1,38 +1,38 @@ --- read_when: - คุณต้องการใช้โมเดล Google Gemini กับ OpenClaw - - คุณต้องใช้คีย์ API หรือโฟลว์การตรวจสอบสิทธิ์ OAuth -summary: การตั้งค่า Google Gemini (คีย์ API + OAuth, การสร้างภาพ, การทำความเข้าใจสื่อ, TTS, การค้นหาเว็บ) + - คุณต้องใช้คีย์ API หรือขั้นตอนการยืนยันตัวตนแบบ OAuth +summary: การตั้งค่า Google Gemini (คีย์ API + OAuth, การสร้างรูปภาพ, การทำความเข้าใจสื่อ, TTS, การค้นหาเว็บ) title: Google (Gemini) x-i18n: - generated_at: "2026-05-02T10:26:17Z" + generated_at: "2026-05-04T07:06:25Z" model: gpt-5.5 provider: openai - source_hash: 14605b88f0d1d7e01796d429113a73b2b52a48fde6443565dcb3db47653be5e7 + source_hash: 3e45627f5d5cd57e858c7590a90435b7fc0e9381509f3312a16fc9e9a4cbd908 source_path: providers/google.md workflow: 16 --- Plugin ของ Google ให้การเข้าถึงโมเดล Gemini ผ่าน Google AI Studio รวมถึง -การสร้างรูปภาพ การทำความเข้าใจสื่อ (รูปภาพ/เสียง/วิดีโอ), การแปลงข้อความเป็นเสียง และการค้นหาเว็บผ่าน +การสร้างภาพ การทำความเข้าใจสื่อ (ภาพ/เสียง/วิดีโอ) การแปลงข้อความเป็นเสียง และการค้นหาเว็บผ่าน Gemini Grounding - ผู้ให้บริการ: `google` - การยืนยันตัวตน: `GEMINI_API_KEY` หรือ `GOOGLE_API_KEY` - API: Google Gemini API -- ตัวเลือก Runtime: `agents.defaults.agentRuntime.id: "google-gemini-cli"` - ใช้ Gemini CLI OAuth ซ้ำ โดยยังคงให้ refs ของโมเดลเป็นรูปแบบ canonical เช่น `google/*` +- ตัวเลือกรันไทม์: `agents.defaults.agentRuntime.id: "google-gemini-cli"` + ใช้ Gemini CLI OAuth ซ้ำ พร้อมคงการอ้างอิงโมเดลให้เป็นรูปแบบมาตรฐานเป็น `google/*` ## เริ่มต้นใช้งาน -เลือกวิธีการยืนยันตัวตนที่ต้องการ แล้วทำตามขั้นตอนการตั้งค่า +เลือกวิธีการยืนยันตัวตนที่ต้องการและทำตามขั้นตอนการตั้งค่า - **เหมาะที่สุดสำหรับ:** การเข้าถึง Gemini API มาตรฐานผ่าน Google AI Studio + **เหมาะสำหรับ:** การเข้าถึง Gemini API มาตรฐานผ่าน Google AI Studio - + ```bash openclaw onboard --auth-choice gemini-api-key ``` @@ -46,7 +46,7 @@ Gemini Grounding --gemini-api-key "$GEMINI_API_KEY" ``` - + ```json5 { agents: { @@ -57,7 +57,7 @@ Gemini Grounding } ``` - + ```bash openclaw models list --provider google ``` @@ -65,22 +65,22 @@ Gemini Grounding - ตัวแปรสภาพแวดล้อม `GEMINI_API_KEY` และ `GOOGLE_API_KEY` ใช้ได้ทั้งคู่ ใช้ตัวที่คุณตั้งค่าไว้อยู่แล้ว + ตัวแปรสภาพแวดล้อม `GEMINI_API_KEY` และ `GOOGLE_API_KEY` ใช้ได้ทั้งคู่ ใช้ตัวที่คุณกำหนดค่าไว้อยู่แล้ว - **เหมาะที่สุดสำหรับ:** การใช้การเข้าสู่ระบบ Gemini CLI ที่มีอยู่ผ่าน PKCE OAuth ซ้ำ แทนการใช้ API key แยกต่างหาก + **เหมาะสำหรับ:** การใช้การเข้าสู่ระบบ Gemini CLI ที่มีอยู่แล้วซ้ำผ่าน PKCE OAuth แทน API key แยกต่างหาก - ผู้ให้บริการ `google-gemini-cli` เป็นการผสานรวมที่ไม่เป็นทางการ ผู้ใช้บางราย - รายงานข้อจำกัดของบัญชีเมื่อใช้ OAuth ด้วยวิธีนี้ ใช้โดยยอมรับความเสี่ยงเอง + ผู้ให้บริการ `google-gemini-cli` เป็นการเชื่อมต่อแบบไม่เป็นทางการ ผู้ใช้บางราย + รายงานว่ามีข้อจำกัดบัญชีเมื่อใช้ OAuth ด้วยวิธีนี้ ใช้โดยยอมรับความเสี่ยงเอง - - คำสั่ง `gemini` ในเครื่องต้องพร้อมใช้งานบน `PATH` + + คำสั่ง `gemini` ภายในเครื่องต้องพร้อมใช้งานบน `PATH` ```bash # Homebrew @@ -90,15 +90,15 @@ Gemini Grounding npm install -g @google/gemini-cli ``` - OpenClaw รองรับทั้งการติดตั้งผ่าน Homebrew และการติดตั้ง npm แบบ global รวมถึง - เลย์เอาต์ Windows/npm ที่พบบ่อย + OpenClaw รองรับทั้งการติดตั้งผ่าน Homebrew และการติดตั้ง npm แบบโกลบอล รวมถึง + โครงสร้าง Windows/npm ทั่วไป - + ```bash openclaw models auth login --provider google-gemini-cli --set-default ``` - + ```bash openclaw models list --provider google ``` @@ -106,10 +106,10 @@ Gemini Grounding - โมเดลเริ่มต้น: `google/gemini-3.1-pro-preview` - - Runtime: `google-gemini-cli` + - รันไทม์: `google-gemini-cli` - นามแฝง: `gemini-cli` - รหัสโมเดล Gemini API ของ Gemini 3.1 Pro คือ `gemini-3.1-pro-preview` OpenClaw รับค่า `google/gemini-3.1-pro` แบบสั้นกว่าเป็นนามแฝงเพื่อความสะดวก และทำให้เป็นรูปแบบปกติก่อนเรียกผู้ให้บริการ + รหัสโมเดล Gemini API ของ Gemini 3.1 Pro คือ `gemini-3.1-pro-preview` OpenClaw รับ `google/gemini-3.1-pro` ที่สั้นกว่าเป็นนามแฝงเพื่อความสะดวก และปรับให้อยู่ในรูปแบบมาตรฐานก่อนเรียกผู้ให้บริการ **ตัวแปรสภาพแวดล้อม:** @@ -119,42 +119,42 @@ Gemini Grounding (หรือรูปแบบ `GEMINI_CLI_*`) - หากคำขอ Gemini CLI OAuth ล้มเหลวหลังเข้าสู่ระบบ ให้ตั้งค่า `GOOGLE_CLOUD_PROJECT` หรือ + หากคำขอ Gemini CLI OAuth ล้มเหลวหลังจากเข้าสู่ระบบ ให้ตั้งค่า `GOOGLE_CLOUD_PROJECT` หรือ `GOOGLE_CLOUD_PROJECT_ID` บนโฮสต์ Gateway แล้วลองอีกครั้ง - หากการเข้าสู่ระบบล้มเหลวก่อนเริ่มขั้นตอนในเบราว์เซอร์ ให้ตรวจสอบว่ามีการติดตั้งคำสั่ง `gemini` - ในเครื่องและอยู่บน `PATH` + หากการเข้าสู่ระบบล้มเหลวก่อนเริ่มโฟลว์เบราว์เซอร์ ตรวจสอบให้แน่ใจว่าคำสั่ง `gemini` + ภายในเครื่องถูกติดตั้งและอยู่บน `PATH` - refs โมเดล `google-gemini-cli/*` เป็นนามแฝงเพื่อความเข้ากันได้แบบเดิม การกำหนดค่าใหม่ - ควรใช้ refs โมเดล `google/*` ร่วมกับ Runtime `google-gemini-cli` - เมื่อต้องการให้ Gemini CLI ทำงานในเครื่อง + การอ้างอิงโมเดล `google-gemini-cli/*` เป็นนามแฝงความเข้ากันได้แบบเดิม การกำหนดค่าใหม่ + ควรใช้การอ้างอิงโมเดล `google/*` พร้อมกับรันไทม์ `google-gemini-cli` + เมื่อต้องการให้ Gemini CLI ทำงานภายในเครื่อง ## ความสามารถ -| ความสามารถ | รองรับ | +| ความสามารถ | รองรับ | | ---------------------- | ----------------------------- | -| การเติมเต็มแชต | ใช่ | -| การสร้างรูปภาพ | ใช่ | -| การสร้างเพลง | ใช่ | -| การแปลงข้อความเป็นเสียง | ใช่ | -| เสียงแบบเรียลไทม์ | ใช่ (Google Live API) | -| การทำความเข้าใจรูปภาพ | ใช่ | -| การถอดเสียงจากเสียง | ใช่ | -| การทำความเข้าใจวิดีโอ | ใช่ | -| การค้นหาเว็บ (Grounding) | ใช่ | -| การคิด/การให้เหตุผล | ใช่ (Gemini 2.5+ / Gemini 3+) | -| โมเดล Gemma 4 | ใช่ | +| การเติมเต็มแชต | ใช่ | +| การสร้างภาพ | ใช่ | +| การสร้างเพลง | ใช่ | +| การแปลงข้อความเป็นเสียง | ใช่ | +| เสียงเรียลไทม์ | ใช่ (Google Live API) | +| การทำความเข้าใจภาพ | ใช่ | +| การถอดเสียง | ใช่ | +| การทำความเข้าใจวิดีโอ | ใช่ | +| การค้นหาเว็บ (Grounding) | ใช่ | +| การคิด/การใช้เหตุผล | ใช่ (Gemini 2.5+ / Gemini 3+) | +| โมเดล Gemma 4 | ใช่ | ## การค้นหาเว็บ -ผู้ให้บริการค้นหาเว็บ `gemini` ที่มาพร้อมชุดใช้งานใช้ Gemini Google Search grounding -กำหนดค่าคีย์ค้นหาเฉพาะภายใต้ `plugins.entries.google.config.webSearch` +ผู้ให้บริการค้นหาเว็บ `gemini` ที่รวมมาให้ใช้ Gemini Google Search grounding +กำหนดค่าคีย์ค้นหาเฉพาะใต้ `plugins.entries.google.config.webSearch` หรือให้ใช้ `models.providers.google.apiKey` ซ้ำหลังจาก `GEMINI_API_KEY`: ```json5 @@ -175,40 +175,40 @@ Gemini Grounding } ``` -ลำดับความสำคัญของข้อมูลประจำตัวคือ `webSearch.apiKey` เฉพาะก่อน จากนั้น `GEMINI_API_KEY` -แล้วจึงเป็น `models.providers.google.apiKey` `webSearch.baseUrl` เป็นค่าไม่บังคับและ -มีไว้สำหรับพร็อกซีของผู้ปฏิบัติงานหรือปลายทาง Gemini API ที่เข้ากันได้ เมื่อไม่ได้ระบุ -การค้นหาเว็บของ Gemini จะใช้ `models.providers.google.baseUrl` ซ้ำ ดู -[การค้นหา Gemini](/th/tools/gemini-search) สำหรับพฤติกรรมเครื่องมือเฉพาะของผู้ให้บริการ +ลำดับความสำคัญของข้อมูลรับรองคือ `webSearch.apiKey` เฉพาะ จากนั้น `GEMINI_API_KEY` +จากนั้น `models.providers.google.apiKey` `webSearch.baseUrl` เป็นตัวเลือกและ +มีไว้สำหรับพร็อกซีของผู้ดำเนินการหรือปลายทาง Gemini API ที่เข้ากันได้ เมื่อไม่ระบุ +การค้นหาเว็บ Gemini จะใช้ `models.providers.google.baseUrl` ซ้ำ ดู +[การค้นหา Gemini](/th/tools/gemini-search) สำหรับพฤติกรรมเครื่องมือเฉพาะผู้ให้บริการ โมเดล Gemini 3 ใช้ `thinkingLevel` แทน `thinkingBudget` OpenClaw แมป -ตัวควบคุมการให้เหตุผลของนามแฝง Gemini 3, Gemini 3.1 และ `gemini-*-latest` ไปยัง -`thinkingLevel` เพื่อให้การรันเริ่มต้น/ความหน่วงต่ำไม่ส่งค่า -`thinkingBudget` ที่ถูกปิดใช้งาน +การควบคุมเหตุผลของนามแฝง Gemini 3, Gemini 3.1 และ `gemini-*-latest` ไปยัง +`thinkingLevel` เพื่อให้การรันแบบค่าเริ่มต้น/หน่วงเวลาต่ำไม่ส่งค่า +`thinkingBudget` ที่ปิดใช้งานแล้ว -`/think adaptive` คง semantics การคิดแบบไดนามิกของ Google ไว้แทนการเลือก -ระดับ OpenClaw แบบตายตัว Gemini 3 และ Gemini 3.1 จะละเว้น `thinkingLevel` แบบตายตัวเพื่อให้ +`/think adaptive` คงความหมายการคิดแบบไดนามิกของ Google แทนการเลือก +ระดับ OpenClaw แบบคงที่ Gemini 3 และ Gemini 3.1 จะละ `thinkingLevel` แบบคงที่เพื่อให้ Google เลือกระดับได้ ส่วน Gemini 2.5 จะส่ง sentinel แบบไดนามิกของ Google `thinkingBudget: -1` โมเดล Gemma 4 (เช่น `gemma-4-26b-a4b-it`) รองรับโหมดการคิด OpenClaw เขียน `thinkingBudget` ใหม่เป็น `thinkingLevel` ของ Google ที่รองรับสำหรับ Gemma 4 -การตั้งค่าการคิดเป็น `off` จะคงการปิดใช้งานการคิดไว้ แทนที่จะแมปเป็น +การตั้งค่าการคิดเป็น `off` จะคงการปิดใช้งานการคิดไว้แทนการแมปเป็น `MINIMAL` -## การสร้างรูปภาพ +## การสร้างภาพ -ผู้ให้บริการสร้างรูปภาพ `google` ที่มาพร้อมชุดใช้งานมีค่าเริ่มต้นเป็น +ผู้ให้บริการสร้างภาพ `google` ที่รวมมาให้ตั้งค่าเริ่มต้นเป็น `google/gemini-3.1-flash-image-preview` - รองรับ `google/gemini-3-pro-image-preview` ด้วย -- สร้าง: ได้สูงสุด 4 รูปภาพต่อคำขอ -- โหมดแก้ไข: เปิดใช้งาน รองรับรูปภาพอินพุตสูงสุด 5 รูป -- ตัวควบคุมเรขาคณิต: `size`, `aspectRatio` และ `resolution` +- สร้าง: สูงสุด 4 ภาพต่อคำขอ +- โหมดแก้ไข: เปิดใช้งาน สูงสุด 5 ภาพอินพุต +- การควบคุมเรขาคณิต: `size`, `aspectRatio` และ `resolution` -หากต้องการใช้ Google เป็นผู้ให้บริการรูปภาพเริ่มต้น: +หากต้องการใช้ Google เป็นผู้ให้บริการภาพเริ่มต้น: ```json5 { @@ -223,18 +223,18 @@ Google เลือกระดับได้ ส่วน Gemini 2.5 จะส ``` -ดู [การสร้างรูปภาพ](/th/tools/image-generation) สำหรับพารามิเตอร์เครื่องมือที่ใช้ร่วมกัน การเลือกผู้ให้บริการ และพฤติกรรม failover +ดู [การสร้างภาพ](/th/tools/image-generation) สำหรับพารามิเตอร์เครื่องมือร่วม การเลือกผู้ให้บริการ และพฤติกรรม failover ## การสร้างวิดีโอ -Plugin `google` ที่มาพร้อมชุดใช้งานยังลงทะเบียนการสร้างวิดีโอผ่านเครื่องมือที่ใช้ร่วมกัน -`video_generate` +Plugin `google` ที่รวมมาให้ยังลงทะเบียนการสร้างวิดีโอผ่านเครื่องมือร่วม +`video_generate` ด้วย - โมเดลวิดีโอเริ่มต้น: `google/veo-3.1-fast-generate-preview` -- โหมด: โฟลว์ข้อความเป็นวิดีโอ รูปภาพเป็นวิดีโอ และการอ้างอิงวิดีโอเดียว +- โหมด: โฟลว์ข้อความเป็นวิดีโอ ภาพเป็นวิดีโอ และอ้างอิงวิดีโอเดียว - รองรับ `aspectRatio`, `resolution` และ `audio` -- ขีดจำกัดระยะเวลาปัจจุบัน: **4 ถึง 8 วินาที** +- การจำกัดระยะเวลาปัจจุบัน: **4 ถึง 8 วินาที** หากต้องการใช้ Google เป็นผู้ให้บริการวิดีโอเริ่มต้น: @@ -251,20 +251,20 @@ Plugin `google` ที่มาพร้อมชุดใช้งานยั ``` -ดู [การสร้างวิดีโอ](/th/tools/video-generation) สำหรับพารามิเตอร์เครื่องมือที่ใช้ร่วมกัน การเลือกผู้ให้บริการ และพฤติกรรม failover +ดู [การสร้างวิดีโอ](/th/tools/video-generation) สำหรับพารามิเตอร์เครื่องมือร่วม การเลือกผู้ให้บริการ และพฤติกรรม failover ## การสร้างเพลง -Plugin `google` ที่มาพร้อมชุดใช้งานยังลงทะเบียนการสร้างเพลงผ่านเครื่องมือที่ใช้ร่วมกัน -`music_generate` +Plugin `google` ที่รวมมาให้ยังลงทะเบียนการสร้างเพลงผ่านเครื่องมือร่วม +`music_generate` ด้วย - โมเดลเพลงเริ่มต้น: `google/lyria-3-clip-preview` - รองรับ `google/lyria-3-pro-preview` ด้วย -- ตัวควบคุมพรอมป์: `lyrics` และ `instrumental` -- รูปแบบเอาต์พุต: `mp3` เป็นค่าเริ่มต้น และมี `wav` เพิ่มเติมบน `google/lyria-3-pro-preview` -- อินพุตอ้างอิง: รูปภาพสูงสุด 10 รูป -- การรันที่มีเซสชันรองรับจะแยกการทำงานผ่านโฟลว์งาน/สถานะที่ใช้ร่วมกัน รวมถึง `action: "status"` +- การควบคุมพรอมป์: `lyrics` และ `instrumental` +- รูปแบบเอาต์พุต: ค่าเริ่มต้นคือ `mp3` รวมถึง `wav` บน `google/lyria-3-pro-preview` +- อินพุตอ้างอิง: สูงสุด 10 ภาพ +- การรันที่มีเซสชันรองรับจะ detach ผ่านโฟลว์งาน/สถานะร่วม รวมถึง `action: "status"` หากต้องการใช้ Google เป็นผู้ให้บริการเพลงเริ่มต้น: @@ -281,18 +281,18 @@ Plugin `google` ที่มาพร้อมชุดใช้งานยั ``` -ดู [การสร้างเพลง](/th/tools/music-generation) สำหรับพารามิเตอร์เครื่องมือที่ใช้ร่วมกัน การเลือกผู้ให้บริการ และพฤติกรรม failover +ดู [การสร้างเพลง](/th/tools/music-generation) สำหรับพารามิเตอร์เครื่องมือร่วม การเลือกผู้ให้บริการ และพฤติกรรม failover ## การแปลงข้อความเป็นเสียง -ผู้ให้บริการเสียง `google` ที่มาพร้อมชุดใช้งานใช้เส้นทาง TTS ของ Gemini API ด้วย +ผู้ให้บริการเสียงพูด `google` ที่รวมมาให้ใช้เส้นทาง TTS ของ Gemini API ด้วย `gemini-3.1-flash-tts-preview` - เสียงเริ่มต้น: `Kore` - การยืนยันตัวตน: `messages.tts.providers.google.apiKey`, `models.providers.google.apiKey`, `GEMINI_API_KEY` หรือ `GOOGLE_API_KEY` - เอาต์พุต: WAV สำหรับไฟล์แนบ TTS ปกติ, Opus สำหรับเป้าหมาย voice-note, PCM สำหรับ Talk/โทรศัพท์ -- เอาต์พุต voice-note: Google PCM จะถูกห่อเป็น WAV และแปลงรหัสเป็น Opus 48 kHz ด้วย `ffmpeg` +- เอาต์พุต voice-note: Google PCM ถูกห่อเป็น WAV และทรานส์โค้ดเป็น Opus 48 kHz ด้วย `ffmpeg` หากต้องการใช้ Google เป็นผู้ให้บริการ TTS เริ่มต้น: @@ -314,13 +314,13 @@ Plugin `google` ที่มาพร้อมชุดใช้งานยั } ``` -Gemini API TTS ใช้การพรอมป์ด้วยภาษาธรรมชาติเพื่อควบคุมสไตล์ ตั้งค่า -`audioProfile` เพื่อเติมพรอมป์สไตล์ที่นำกลับมาใช้ซ้ำได้ไว้หน้าข้อความที่จะพูด ตั้งค่า +Gemini API TTS ใช้การพรอมป์ด้วยภาษาธรรมชาติสำหรับควบคุมสไตล์ ตั้งค่า +`audioProfile` เพื่อเติมพรอมป์สไตล์ที่ใช้ซ้ำได้ไว้ก่อนข้อความที่จะพูด ตั้งค่า `speakerName` เมื่อข้อความพรอมป์ของคุณอ้างถึงผู้พูดที่มีชื่อ -Gemini API TTS ยังรับแท็กเสียงในวงเล็บเหลี่ยมแบบแสดงอารมณ์ในข้อความ -เช่น `[whispers]` หรือ `[laughs]` หากต้องการกันแท็กออกจากข้อความตอบกลับแชตที่มองเห็น -แต่ยังส่งไปยัง TTS ให้วางไว้ภายในบล็อก `[[tts:text]]...[[/tts:text]]`: +Gemini API TTS ยังรับแท็กเสียงแบบวงเล็บเหลี่ยมที่สื่ออารมณ์ในข้อความ +เช่น `[whispers]` หรือ `[laughs]` หากต้องการกันแท็กออกจากคำตอบแชตที่มองเห็นได้ +ในขณะที่ส่งแท็กเหล่านั้นไปยัง TTS ให้ใส่แท็กไว้ในบล็อก `[[tts:text]]...[[/tts:text]]`: ```text Here is the clean reply text. @@ -329,29 +329,31 @@ Here is the clean reply text. ``` -API key ของ Google Cloud Console ที่จำกัดไว้สำหรับ Gemini API ใช้ได้กับ +API key ของ Google Cloud Console ที่จำกัดไว้กับ Gemini API ใช้ได้กับ ผู้ให้บริการนี้ นี่ไม่ใช่เส้นทาง Cloud Text-to-Speech API แยกต่างหาก -## เสียงแบบเรียลไทม์ +## เสียงเรียลไทม์ -Plugin `google` ที่มาพร้อมชุดใช้งานลงทะเบียนผู้ให้บริการเสียงแบบเรียลไทม์ที่ใช้ -Gemini Live API สำหรับบริดจ์เสียงฝั่งแบ็กเอนด์ เช่น Voice Call และ Google Meet +Plugin `google` ที่รวมมาให้ลงทะเบียนผู้ให้บริการเสียงเรียลไทม์ที่ขับเคลื่อนโดย +Gemini Live API สำหรับบริดจ์เสียงแบ็กเอนด์ เช่น Voice Call และ Google Meet | การตั้งค่า | พาธการกำหนดค่า | ค่าเริ่มต้น | | --------------------- | ------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | -| Model | `plugins.entries.voice-call.config.realtime.providers.google.model` | `gemini-2.5-flash-native-audio-preview-12-2025` | -| Voice | `...google.voice` | `Kore` | -| Temperature | `...google.temperature` | (ไม่ได้ตั้งค่า) | -| ความไวเริ่มต้นของ VAD | `...google.startSensitivity` | (ไม่ได้ตั้งค่า) | -| ความไวสิ้นสุดของ VAD | `...google.endSensitivity` | (ไม่ได้ตั้งค่า) | -| ระยะเวลาความเงียบ | `...google.silenceDurationMs` | (ไม่ได้ตั้งค่า) | +| โมเดล | `plugins.entries.voice-call.config.realtime.providers.google.model` | `gemini-2.5-flash-native-audio-preview-12-2025` | +| เสียง | `...google.voice` | `Kore` | +| อุณหภูมิ | `...google.temperature` | (ไม่ได้ตั้งค่า) | +| ความไวในการเริ่ม VAD | `...google.startSensitivity` | (ไม่ได้ตั้งค่า) | +| ความไวในการจบ VAD | `...google.endSensitivity` | (ไม่ได้ตั้งค่า) | +| ระยะเวลาเงียบ | `...google.silenceDurationMs` | (ไม่ได้ตั้งค่า) | | การจัดการกิจกรรม | `...google.activityHandling` | ค่าเริ่มต้นของ Google, `start-of-activity-interrupts` | | ความครอบคลุมของเทิร์น | `...google.turnCoverage` | ค่าเริ่มต้นของ Google, `only-activity` | | ปิดใช้งาน VAD อัตโนมัติ | `...google.automaticActivityDetectionDisabled` | `false` | -| คีย์ API | `...google.apiKey` | สำรองไปใช้ `models.providers.google.apiKey`, `GEMINI_API_KEY`, หรือ `GOOGLE_API_KEY` | +| การกลับมาใช้เซสชันต่อ | `...google.sessionResumption` | `true` | +| การบีบอัดบริบท | `...google.contextWindowCompression` | `true` | +| คีย์ API | `...google.apiKey` | ถอยกลับไปใช้ `models.providers.google.apiKey`, `GEMINI_API_KEY`, หรือ `GOOGLE_API_KEY` | -ตัวอย่างการกำหนดค่าเรียลไทม์ของการโทรด้วยเสียง: +ตัวอย่างการกำหนดค่าเรียลไทม์ของ Voice Call: ```json5 { @@ -381,24 +383,24 @@ Gemini Live API สำหรับบริดจ์เสียงฝั่ง Google Live API ใช้เสียงสองทิศทางและการเรียกฟังก์ชันผ่าน WebSocket -OpenClaw ปรับเสียงจากบริดจ์โทรศัพท์/Meet ให้เข้ากับสตรีม PCM Live API ของ Gemini และ -คงการเรียกใช้เครื่องมือไว้บนสัญญาเสียงเรียลไทม์ที่ใช้ร่วมกัน ปล่อย `temperature` -ให้ไม่ได้ตั้งค่าไว้ เว้นแต่คุณต้องการเปลี่ยนการสุ่มตัวอย่าง OpenClaw จะละค่าที่ไม่เป็นบวก -เพราะ Google Live อาจส่งคืนทรานสคริปต์โดยไม่มีเสียงสำหรับ `temperature: 0` +OpenClaw ปรับเสียงจากสะพานเชื่อมโทรศัพท์/Meet ให้เข้ากับสตรีม PCM Live API ของ Gemini และ +คงการเรียกเครื่องมือไว้บนสัญญาเสียงเรียลไทม์ที่ใช้ร่วมกัน ปล่อย `temperature` +ไว้โดยไม่ต้องตั้งค่า เว้นแต่คุณต้องเปลี่ยนการสุ่มตัวอย่าง OpenClaw จะละเว้นค่าที่ไม่เป็นบวก +เพราะ Google Live อาจส่งทรานสคริปต์กลับมาโดยไม่มีเสียงสำหรับ `temperature: 0` การถอดเสียงของ Gemini API เปิดใช้งานโดยไม่มี `languageCodes`; Google -SDK ปัจจุบันปฏิเสธคำแนะนำรหัสภาษาบนพาธ API นี้ +SDK ปัจจุบันปฏิเสธคำใบ้รหัสภาษาบนพาธ API นี้ -Control UI Talk รองรับเซสชัน Google Live บนเบราว์เซอร์ด้วยโทเค็นแบบใช้ครั้งเดียวที่มีข้อจำกัด -ผู้ให้บริการเสียงเรียลไทม์เฉพาะแบ็กเอนด์ยังสามารถทำงานผ่านทรานสปอร์ตรีเลย์ทั่วไปของ -Gateway ซึ่งเก็บข้อมูลรับรองของผู้ให้บริการไว้บน Gateway +Control UI Talk รองรับเซสชัน Google Live ในเบราว์เซอร์ด้วยโทเค็นใช้ครั้งเดียวแบบจำกัด +ผู้ให้บริการเสียงเรียลไทม์แบบแบ็กเอนด์เท่านั้นยังสามารถทำงานผ่านการขนส่งรีเลย์ทั่วไปของ +Gateway ได้ด้วย ซึ่งจะเก็บข้อมูลประจำตัวของผู้ให้บริการไว้บน Gateway สำหรับการตรวจสอบสดของผู้ดูแล ให้รัน -`OPENAI_API_KEY=... GEMINI_API_KEY=... node --import tsx scripts/dev/realtime-talk-live-smoke.ts`. -ส่วนของ Google จะสร้างโทเค็น Live API ที่มีข้อจำกัดในรูปแบบเดียวกับที่ Control -UI Talk ใช้ เปิดปลายทาง WebSocket ของเบราว์เซอร์ ส่งเพย์โหลดการตั้งค่าเริ่มต้น +`OPENAI_API_KEY=... GEMINI_API_KEY=... node --import tsx scripts/dev/realtime-talk-live-smoke.ts` +ฝั่ง Google จะออกโทเค็น Live API แบบจำกัดรูปแบบเดียวกับที่ Control +UI Talk ใช้ เปิดปลายทาง WebSocket ของเบราว์เซอร์ ส่งเพย์โหลดตั้งค่าเริ่มต้น และรอ `setupComplete` ## การกำหนดค่าขั้นสูง @@ -406,13 +408,13 @@ UI Talk ใช้ เปิดปลายทาง WebSocket ของเบร สำหรับการรัน Gemini API โดยตรง (`api: "google-generative-ai"`), OpenClaw - ส่งแฮนเดิล `cachedContent` ที่กำหนดค่าไว้ต่อไปยังคำขอ Gemini + จะส่งต่อแฮนเดิล `cachedContent` ที่กำหนดค่าไว้ไปยังคำขอ Gemini - กำหนดค่าพารามิเตอร์ต่อโมเดลหรือส่วนกลางด้วย `cachedContent` หรือ `cached_content` แบบเดิม - - หากมีทั้งสองค่า `cachedContent` จะชนะ + - หากมีทั้งสองค่า `cachedContent` จะมีผลก่อน - ค่าตัวอย่าง: `cachedContents/prebuilt-context` - - การใช้งาน cache-hit ของ Gemini จะถูกปรับให้อยู่ในรูป OpenClaw `cacheRead` จาก + - การใช้งาน cache-hit ของ Gemini ถูกทำให้เป็นรูปแบบมาตรฐานเป็น `cacheRead` ของ OpenClaw จาก `cachedContentTokenCount` ต้นทาง ```json5 @@ -434,20 +436,20 @@ UI Talk ใช้ เปิดปลายทาง WebSocket ของเบร - เมื่อใช้ผู้ให้บริการ OAuth `google-gemini-cli`, OpenClaw จะปรับ - เอาต์พุต CLI JSON ให้เป็นดังนี้: + เมื่อใช้ผู้ให้บริการ OAuth `google-gemini-cli`, OpenClaw จะทำให้ + เอาต์พุต JSON ของ CLI เป็นรูปแบบมาตรฐานดังนี้: - - ข้อความตอบกลับมาจากฟิลด์ CLI JSON `response` - - การใช้งานสำรองไปใช้ `stats` เมื่อ CLI ปล่อย `usage` ว่างไว้ - - `stats.cached` จะถูกปรับให้อยู่ในรูป OpenClaw `cacheRead` + - ข้อความตอบกลับมาจากฟิลด์ `response` ใน JSON ของ CLI + - การใช้งานจะถอยกลับไปใช้ `stats` เมื่อ CLI ปล่อย `usage` ว่างไว้ + - `stats.cached` ถูกทำให้เป็นรูปแบบมาตรฐานเป็น `cacheRead` ของ OpenClaw - หากไม่มี `stats.input`, OpenClaw จะคำนวณโทเค็นอินพุตจาก `stats.input_tokens - stats.cached` - หาก Gateway ทำงานเป็น daemon (launchd/systemd) ตรวจสอบให้แน่ใจว่า `GEMINI_API_KEY` - พร้อมใช้งานสำหรับโปรเซสนั้น (เช่น ใน `~/.openclaw/.env` หรือผ่าน + หาก Gateway ทำงานเป็น daemon (launchd/systemd), ตรวจสอบให้แน่ใจว่า `GEMINI_API_KEY` + พร้อมใช้งานสำหรับกระบวนการนั้น (เช่น ใน `~/.openclaw/.env` หรือผ่าน `env.shellEnv`) @@ -456,7 +458,7 @@ UI Talk ใช้ เปิดปลายทาง WebSocket ของเบร - การเลือกผู้ให้บริการ, การอ้างอิงโมเดล, และพฤติกรรม failover + การเลือกผู้ให้บริการ การอ้างอิงโมเดล และพฤติกรรมการสลับสำรอง พารามิเตอร์เครื่องมือรูปภาพที่ใช้ร่วมกันและการเลือกผู้ให้บริการ diff --git a/docs/th/reference/RELEASING.md b/docs/th/reference/RELEASING.md index ece5c79b6..acfc5fc3e 100644 --- a/docs/th/reference/RELEASING.md +++ b/docs/th/reference/RELEASING.md @@ -2,172 +2,273 @@ read_when: - กำลังค้นหานิยามช่องทางการเผยแพร่สาธารณะ - การเรียกใช้การตรวจสอบความถูกต้องของรีลีสหรือการยอมรับแพ็กเกจ - - กำลังมองหารูปแบบการตั้งชื่อเวอร์ชันและจังหวะการออกเวอร์ชัน -summary: เลนการเผยแพร่, รายการตรวจสอบสำหรับผู้ปฏิบัติงาน, กล่องตรวจสอบความถูกต้อง, การตั้งชื่อเวอร์ชัน และรอบการเผยแพร่ -title: นโยบายการเผยแพร่รุ่น + - กำลังค้นหารูปแบบการตั้งชื่อเวอร์ชันและรอบการออกรุ่น +summary: เลนการเผยแพร่, รายการตรวจสอบสำหรับผู้ปฏิบัติการ, กล่องตรวจสอบความถูกต้อง, การตั้งชื่อเวอร์ชัน และรอบการเผยแพร่ +title: นโยบายการเผยแพร่ x-i18n: - generated_at: "2026-05-03T21:36:10Z" + generated_at: "2026-05-04T07:06:35Z" model: gpt-5.5 provider: openai - source_hash: 566088d826e1e2bac21b11443b82b62cb73ed1fd9c508c3fb865149cf8a428ba + source_hash: ef50d3ef5d1e23b4e2c2b097fc4ca9f6d46bf8acb9aea0c9bca6d14e213b88b6 source_path: reference/RELEASING.md workflow: 16 --- -OpenClaw มีเลนรีลีสสาธารณะสามเลน: +OpenClaw มีเลนการเผยแพร่สาธารณะสามเลน: -- stable: รีลีสที่ติดแท็กซึ่งเผยแพร่ไปยัง npm `beta` ตามค่าเริ่มต้น หรือไปยัง npm `latest` เมื่อร้องขออย่างชัดเจน -- beta: แท็ก prerelease ที่เผยแพร่ไปยัง npm `beta` -- dev: หัวที่เคลื่อนไหวของ `main` +- stable: รุ่นเผยแพร่ที่ติดแท็ก ซึ่งเผยแพร่ไปยัง npm `beta` ตามค่าเริ่มต้น หรือไปยัง npm `latest` เมื่อมีการร้องขออย่างชัดเจน +- beta: แท็กก่อนเผยแพร่ที่เผยแพร่ไปยัง npm `beta` +- dev: หัวปัจจุบันที่เปลี่ยนแปลงอยู่ของ `main` ## การตั้งชื่อเวอร์ชัน -- เวอร์ชันรีลีส stable: `YYYY.M.D` +- เวอร์ชันรุ่นเผยแพร่เสถียร: `YYYY.M.D` - แท็ก Git: `vYYYY.M.D` -- เวอร์ชันรีลีสแก้ไข stable: `YYYY.M.D-N` +- เวอร์ชันรุ่นเผยแพร่แก้ไขของรุ่นเสถียร: `YYYY.M.D-N` - แท็ก Git: `vYYYY.M.D-N` -- เวอร์ชัน prerelease beta: `YYYY.M.D-beta.N` +- เวอร์ชันก่อนเผยแพร่ Beta: `YYYY.M.D-beta.N` - แท็ก Git: `vYYYY.M.D-beta.N` - อย่าเติมศูนย์นำหน้าเดือนหรือวัน -- `latest` หมายถึงรีลีส npm stable ที่โปรโมตอยู่ในปัจจุบัน +- `latest` หมายถึงรุ่นเผยแพร่ npm เสถียรที่ได้รับการโปรโมตในปัจจุบัน - `beta` หมายถึงเป้าหมายการติดตั้ง beta ปัจจุบัน -- รีลีส stable และรีลีสแก้ไข stable จะเผยแพร่ไปยัง npm `beta` ตามค่าเริ่มต้น; ผู้ปฏิบัติการรีลีสสามารถระบุเป้าหมายเป็น `latest` อย่างชัดเจน หรือโปรโมตบิลด์ beta ที่ผ่านการตรวจสอบภายหลังได้ -- รีลีส OpenClaw stable ทุกครั้งจะส่งแพ็กเกจ npm และแอป macOS พร้อมกัน; - รีลีส beta โดยปกติจะตรวจสอบความถูกต้องและเผยแพร่เส้นทาง npm/package ก่อน โดย - สงวนการ build/sign/notarize แอป mac ไว้สำหรับ stable เว้นแต่จะร้องขออย่างชัดเจน +- รุ่นเผยแพร่เสถียรและรุ่นเผยแพร่แก้ไขของรุ่นเสถียรจะเผยแพร่ไปยัง npm `beta` ตามค่าเริ่มต้น; ผู้ดำเนินการเผยแพร่สามารถกำหนดเป้าหมาย `latest` อย่างชัดเจน หรือโปรโมตบิลด์ beta ที่ตรวจสอบแล้วในภายหลังได้ +- OpenClaw รุ่นเผยแพร่เสถียรทุกเวอร์ชันจะส่งแพ็กเกจ npm และแอป macOS พร้อมกัน; + รุ่น beta โดยปกติจะตรวจสอบและเผยแพร่เส้นทาง npm/แพ็กเกจก่อน โดยสงวนการ build/sign/notarize แอป Mac ไว้สำหรับรุ่นเสถียร เว้นแต่จะมีการร้องขออย่างชัดเจน -## รอบการออกรีลีส +## จังหวะการเผยแพร่ -- รีลีสจะเดินหน้าแบบ beta ก่อน -- stable จะตามมาหลังจาก beta ล่าสุดผ่านการตรวจสอบแล้วเท่านั้น -- โดยปกติ maintainer จะตัดรีลีสจากสาขา `release/YYYY.M.D` ที่สร้างจาก - `main` ปัจจุบัน เพื่อให้การตรวจสอบรีลีสและการแก้ไขไม่บล็อกการพัฒนาใหม่ - บน `main` -- หากมีการ push หรือเผยแพร่แท็ก beta แล้วและต้องแก้ไข maintainer จะตัด - แท็ก `-beta.N` ถัดไปแทนการลบหรือสร้างแท็ก beta เดิมใหม่ -- ขั้นตอนรีลีสโดยละเอียด การอนุมัติ ข้อมูลรับรอง และบันทึกการกู้คืนเป็น - เฉพาะ maintainer เท่านั้น +- การเผยแพร่จะเดินหน้าแบบ beta-first +- รุ่นเสถียรจะตามมาหลังจาก beta ล่าสุดได้รับการตรวจสอบแล้วเท่านั้น +- โดยปกติผู้ดูแลจะตัดรุ่นจากสาขา `release/YYYY.M.D` ที่สร้างจาก `main` ปัจจุบัน เพื่อให้การตรวจสอบรุ่นเผยแพร่และการแก้ไขไม่บล็อกการพัฒนาใหม่บน `main` +- หากแท็ก beta ถูก push หรือเผยแพร่แล้วและต้องการการแก้ไข ผู้ดูแลจะตัดแท็ก `-beta.N` ถัดไปแทนการลบหรือสร้างแท็ก beta เก่าใหม่ +- ขั้นตอนการเผยแพร่โดยละเอียด การอนุมัติ ข้อมูลประจำตัว และบันทึกการกู้คืนมีไว้สำหรับผู้ดูแลเท่านั้น -## เช็กลิสต์ผู้ปฏิบัติการรีลีส +## เช็กลิสต์ผู้ดำเนินการเผยแพร่ -เช็กลิสต์นี้คือรูปแบบสาธารณะของโฟลว์รีลีส ข้อมูลรับรองส่วนตัว, -การลงนาม, การ notarization, การกู้คืน dist-tag และรายละเอียดการ rollback ฉุกเฉินจะอยู่ใน -runbook รีลีสเฉพาะ maintainer เท่านั้น +เช็กลิสต์นี้คือโครงร่างสาธารณะของโฟลว์การเผยแพร่ ข้อมูลประจำตัวส่วนตัว, +การลงนาม, notarization, การกู้คืน dist-tag และรายละเอียดการ rollback ฉุกเฉินยังอยู่ใน +runbook การเผยแพร่สำหรับผู้ดูแลเท่านั้น 1. เริ่มจาก `main` ปัจจุบัน: pull ล่าสุด ยืนยันว่า commit เป้าหมายถูก push แล้ว - และยืนยันว่า CI ของ `main` ปัจจุบันเขียวพอที่จะสร้างสาขาจากมันได้ + และยืนยันว่า CI ของ `main` ปัจจุบันเขียวพอที่จะสร้างสาขาจากมัน 2. เขียนส่วนบนสุดของ `CHANGELOG.md` ใหม่จากประวัติ commit จริงด้วย - `/changelog` รักษารายการให้เป็นเนื้อหาสำหรับผู้ใช้ commit แล้ว push จากนั้น rebase/pull + `/changelog` เก็บรายการให้เป็นเนื้อหาสำหรับผู้ใช้ commit แล้ว push และ rebase/pull อีกครั้งก่อนสร้างสาขา -3. ตรวจทานบันทึกความเข้ากันได้ของรีลีสใน +3. ตรวจทานบันทึกความเข้ากันได้ของรุ่นเผยแพร่ใน `src/plugins/compat/registry.ts` และ `src/commands/doctor/shared/deprecation-compat.ts` ลบความเข้ากันได้ที่หมดอายุ - เฉพาะเมื่อเส้นทางการอัปเกรดยังถูกครอบคลุม หรือบันทึกเหตุผลว่าทำไมจึง - ตั้งใจคงไว้ -4. สร้าง `release/YYYY.M.D` จาก `main` ปัจจุบัน; อย่าทำงานรีลีสปกติ + เฉพาะเมื่อเส้นทางอัปเกรดยังคงครอบคลุมอยู่ หรือบันทึกเหตุผลว่าทำไมจึงตั้งใจคงไว้ +4. สร้าง `release/YYYY.M.D` จาก `main` ปัจจุบัน; อย่าทำงานเผยแพร่ปกติ โดยตรงบน `main` -5. เพิ่มเวอร์ชันทุกตำแหน่งที่จำเป็นสำหรับแท็กที่ตั้งใจไว้ รัน - `pnpm plugins:sync` เพื่อให้แพ็กเกจ Plugin ที่เผยแพร่ได้ใช้เวอร์ชันรีลีส - และเมตาดาต้าความเข้ากันได้ร่วมกัน จากนั้นรัน preflight แบบกำหนดผลลัพธ์ได้ในเครื่อง: +5. เพิ่มเวอร์ชันในทุกตำแหน่งที่จำเป็นสำหรับแท็กที่ตั้งใจไว้ รัน + `pnpm plugins:sync` เพื่อให้แพ็กเกจ Plugin ที่เผยแพร่ได้ใช้เวอร์ชันรุ่นเผยแพร่ + และ metadata ความเข้ากันได้ร่วมกัน จากนั้นรัน preflight แบบกำหนดแน่นอนในเครื่อง: `pnpm check:test-types`, `pnpm check:architecture`, `pnpm build && pnpm ui:build`, `pnpm plugins:sync:check` และ `pnpm release:check` -6. รัน `OpenClaw NPM Release` พร้อม `preflight_only=true` ก่อนมีแท็ก - SHA ของสาขารีลีสแบบเต็ม 40 อักขระอนุญาตให้ใช้สำหรับ preflight - เพื่อการตรวจสอบเท่านั้น บันทึก `preflight_run_id` ที่สำเร็จไว้ -7. เริ่มการทดสอบก่อนรีลีสทั้งหมดด้วย `Full Release Validation` สำหรับ - สาขารีลีส แท็ก หรือ SHA commit แบบเต็ม นี่คือ entrypoint แบบแมนนวลหนึ่งเดียว - สำหรับกล่องทดสอบรีลีสขนาดใหญ่ทั้งสี่: Vitest, Docker, QA Lab และ Package -8. หากการตรวจสอบล้มเหลว ให้แก้บนสาขารีลีสและรันซ้ำเฉพาะไฟล์ เลน งาน workflow, - โปรไฟล์แพ็กเกจ provider หรือ allowlist ของโมเดลที่ล้มเหลวที่เล็กที่สุดซึ่ง - พิสูจน์การแก้ไขได้ รัน umbrella เต็มซ้ำเฉพาะเมื่อพื้นผิวที่เปลี่ยนแปลงทำให้ - หลักฐานก่อนหน้าล้าสมัย -9. สำหรับ beta ให้แท็ก `vYYYY.M.D-beta.N` จากนั้นรัน `OpenClaw Release Publish` จาก - สาขา `release/YYYY.M.D` ที่ตรงกัน โดยจะตรวจสอบ `pnpm plugins:sync:check`, - เผยแพร่แพ็กเกจ Plugin ที่เผยแพร่ได้ทั้งหมดไปยัง npm ก่อน เผยแพร่ชุดเดียวกัน - ไปยัง ClawHub เป็นลำดับที่สองในรูปแบบ ClawPack npm-pack tarball แล้วจึงโปรโมต - artifact preflight ของ OpenClaw npm ที่เตรียมไว้พร้อม dist-tag ที่ตรงกัน หลังจาก - เผยแพร่แล้ว ให้รัน package - acceptance หลังเผยแพร่กับแพ็กเกจ `openclaw@YYYY.M.D-beta.N` หรือ - `openclaw@beta` ที่เผยแพร่แล้ว หาก prerelease ที่ถูก push หรือเผยแพร่แล้วต้องแก้ไข - ให้ตัดหมายเลข prerelease ถัดไปที่ตรงกัน; อย่าลบหรือเขียน prerelease เดิมใหม่ -10. สำหรับ stable ให้ดำเนินต่อเฉพาะหลังจาก beta หรือ release candidate ที่ผ่านการตรวจสอบแล้วมี - หลักฐานการตรวจสอบที่จำเป็น การเผยแพร่ npm stable ก็ผ่าน - `OpenClaw Release Publish` เช่นกัน โดยใช้ artifact preflight ที่สำเร็จซ้ำผ่าน - `preflight_run_id`; ความพร้อมของรีลีส macOS stable ยังต้องมี +6. รัน `OpenClaw NPM Release` ด้วย `preflight_only=true` ก่อนมีแท็ก + อนุญาตให้ใช้ SHA ของสาขารุ่นเผยแพร่แบบเต็ม 40 อักขระสำหรับ preflight + เพื่อการตรวจสอบเท่านั้น บันทึก `preflight_run_id` ที่สำเร็จ +7. เริ่มการทดสอบก่อนเผยแพร่ทั้งหมดด้วย `Full Release Validation` สำหรับ + สาขารุ่นเผยแพร่ แท็ก หรือ SHA commit แบบเต็ม นี่คือ entrypoint แบบ manual เดียว + สำหรับกล่องทดสอบรุ่นเผยแพร่ขนาดใหญ่สี่ชุด: Vitest, Docker, QA Lab และ Package +8. หากการตรวจสอบล้มเหลว ให้แก้บนสาขารุ่นเผยแพร่และรันไฟล์ เลน งาน workflow + โปรไฟล์แพ็กเกจ provider หรือรายการ allowlist ของโมเดลที่ล้มเหลวที่เล็กที่สุด + ซึ่งพิสูจน์การแก้ไขได้ รัน umbrella แบบเต็มอีกครั้งเฉพาะเมื่อพื้นผิวที่เปลี่ยนทำให้ + หลักฐานก่อนหน้าเก่าเกินใช้ +9. สำหรับ beta ให้ติดแท็ก `vYYYY.M.D-beta.N` จากนั้นรัน `OpenClaw Release Publish` จาก + สาขา `release/YYYY.M.D` ที่ตรงกัน ระบบจะตรวจสอบ `pnpm plugins:sync:check`, + เผยแพร่แพ็กเกจ Plugin ที่เผยแพร่ได้ทั้งหมดไปยัง npm ก่อน, เผยแพร่ชุดเดียวกัน + ไปยัง ClawHub เป็นลำดับที่สองในรูปแบบ tarball ClawPack npm-pack แล้วจึงโปรโมต + artifact preflight ของ OpenClaw npm ที่เตรียมไว้ด้วย dist-tag ที่ตรงกัน หลังเผยแพร่ + ให้รันการยอมรับแพ็กเกจหลังเผยแพร่กับแพ็กเกจ `openclaw@YYYY.M.D-beta.N` หรือ + `openclaw@beta` ที่เผยแพร่แล้ว หาก prerelease ที่ถูก push หรือเผยแพร่แล้วต้องการการแก้ไข + ให้ตัดหมายเลข prerelease ถัดไปที่ตรงกัน; อย่าลบหรือเขียน prerelease เก่าใหม่ +10. สำหรับรุ่นเสถียร ให้ดำเนินการต่อเฉพาะหลังจาก beta หรือ release candidate + ที่ตรวจสอบแล้วมีหลักฐานการตรวจสอบที่จำเป็น การเผยแพร่ npm รุ่นเสถียรก็ผ่าน + `OpenClaw Release Publish` เช่นกัน โดยนำ artifact preflight ที่สำเร็จกลับมาใช้ผ่าน + `preflight_run_id`; ความพร้อมของรุ่นเผยแพร่ macOS เสถียรยังต้องมี `.zip`, `.dmg`, `.dSYM.zip` ที่แพ็กแล้ว และ `appcast.xml` ที่อัปเดตบน `main` -11. หลังเผยแพร่ ให้รันตัวตรวจสอบ npm หลังเผยแพร่, Telegram E2E แบบ standalone - published-npm ที่เป็นทางเลือกเมื่อคุณต้องการหลักฐานช่องทางหลังเผยแพร่, - การโปรโมต dist-tag เมื่อจำเป็น, โน้ตรีลีส/prerelease ของ GitHub จาก - ส่วน `CHANGELOG.md` ที่ตรงกันครบถ้วน และขั้นตอนการประกาศรีลีส +11. หลังเผยแพร่ ให้รันตัวตรวจสอบหลังเผยแพร่ของ npm, E2E ของ Telegram จาก published-npm + แบบ standalone ที่เป็นทางเลือกเมื่อคุณต้องการหลักฐานช่องทางหลังเผยแพร่, + การโปรโมต dist-tag เมื่อจำเป็น, บันทึก release/prerelease ของ GitHub จากส่วน + `CHANGELOG.md` ที่ตรงกันครบถ้วน และขั้นตอนประกาศรุ่นเผยแพร่ -## การตรวจสอบก่อนออกรีลีส +## Release preflight -- เรียกใช้ `pnpm check:test-types` ก่อนการตรวจสอบก่อนเผยแพร่ เพื่อให้ TypeScript ของการทดสอบยังได้รับการครอบคลุมนอกเหนือจาก gate `pnpm check` ในเครื่องที่เร็วกว่า -- เรียกใช้ `pnpm check:architecture` ก่อนการตรวจสอบก่อนเผยแพร่ เพื่อให้การตรวจสอบ import cycle และขอบเขตสถาปัตยกรรมที่กว้างขึ้นผ่านเป็นสีเขียวนอกเหนือจาก gate ในเครื่องที่เร็วกว่า -- เรียกใช้ `pnpm build && pnpm ui:build` ก่อน `pnpm release:check` เพื่อให้มีอาร์ติแฟกต์เผยแพร่ `dist/*` และบันเดิล Control UI ที่คาดไว้สำหรับขั้นตอนตรวจสอบ pack -- เรียกใช้ `pnpm plugins:sync` หลังการปรับเวอร์ชันที่ root และก่อนติดแท็ก คำสั่งนี้อัปเดตเวอร์ชันแพ็กเกจ Plugin ที่เผยแพร่ได้, metadata ความเข้ากันได้ของ peer/API ของ OpenClaw, metadata การ build และ stub changelog ของ Plugin ให้ตรงกับเวอร์ชันเผยแพร่ของ core `pnpm plugins:sync:check` คือ guard การเผยแพร่แบบไม่แก้ไขข้อมูล; workflow เผยแพร่จะล้มเหลวก่อนมีการแก้ไข registry ใด ๆ หากลืมขั้นตอนนี้ -- เรียกใช้ workflow แบบ manual `Full Release Validation` ก่อนอนุมัติการเผยแพร่ เพื่อเริ่มกล่องทดสอบก่อนเผยแพร่ทั้งหมดจาก entrypoint เดียว Workflow นี้รับ branch, tag หรือ SHA ของ commit แบบเต็ม, dispatch `CI` แบบ manual และ dispatch `OpenClaw Release Checks` สำหรับ install smoke, package acceptance, ชุดทดสอบ Docker release-path, live/E2E, OpenWebUI, QA Lab parity, Matrix และ lane ของ Telegram เมื่อใช้ `release_profile=full` และ `rerun_group=all` จะเรียกใช้ package Telegram E2E กับอาร์ติแฟกต์ `release-package-under-test` จาก release checks ด้วย ระบุ `npm_telegram_package_spec` หลังเผยแพร่เมื่อ Telegram E2E เดียวกันควรพิสูจน์แพ็กเกจ npm ที่เผยแพร่แล้วด้วย ระบุ `package_acceptance_package_spec` หลังเผยแพร่เมื่อ Package Acceptance ควรเรียกใช้เมทริกซ์ package/update กับแพ็กเกจ npm ที่ส่งมอบแล้ว แทนอาร์ติแฟกต์ที่ build จาก SHA ระบุ `evidence_package_spec` เมื่อรายงานหลักฐานส่วนตัวควรพิสูจน์ว่าการตรวจสอบตรงกับแพ็กเกจ npm ที่เผยแพร่แล้วโดยไม่บังคับใช้ Telegram E2E ตัวอย่าง: `gh workflow run full-release-validation.yml --ref main -f ref=release/YYYY.M.D` -- เรียกใช้ workflow แบบ manual `Package Acceptance` เมื่อคุณต้องการหลักฐาน side-channel สำหรับ candidate ของแพ็กเกจขณะที่งานเผยแพร่ยังดำเนินต่อ ใช้ `source=npm` สำหรับ `openclaw@beta`, `openclaw@latest` หรือเวอร์ชันเผยแพร่แบบระบุชัดเจน; `source=ref` เพื่อ pack branch/tag/SHA ของ `package_ref` ที่เชื่อถือได้ด้วย harness `workflow_ref` ปัจจุบัน; `source=url` สำหรับ tarball HTTPS พร้อม SHA-256 ที่บังคับ; หรือ `source=artifact` สำหรับ tarball ที่อัปโหลดโดย GitHub Actions run อื่น Workflow จะแปลง candidate เป็น `package-under-test`, นำ release scheduler ของ Docker E2E มาใช้ซ้ำกับ tarball นั้น และสามารถเรียกใช้ Telegram QA กับ tarball เดียวกันด้วย `telegram_mode=mock-openai` หรือ `telegram_mode=live-frontier` เมื่อ Docker lane ที่เลือกมี `published-upgrade-survivor` อาร์ติแฟกต์แพ็กเกจคือ candidate และ `published_upgrade_survivor_baseline` จะเลือก baseline ที่เผยแพร่แล้ว +- เรียกใช้ `pnpm check:test-types` ก่อนการ preflight รีลีส เพื่อให้ TypeScript ของการทดสอบยังคง + ครอบคลุมอยู่นอก gate `pnpm check` แบบ local ที่เร็วกว่า +- เรียกใช้ `pnpm check:architecture` ก่อนการ preflight รีลีส เพื่อให้การตรวจสอบ import + cycle และขอบเขตสถาปัตยกรรมที่กว้างขึ้นเป็นสีเขียวอยู่นอก gate แบบ local ที่เร็วกว่า +- เรียกใช้ `pnpm build && pnpm ui:build` ก่อน `pnpm release:check` เพื่อให้อาร์ติแฟกต์รีลีส + `dist/*` ที่คาดไว้และบันเดิล Control UI มีอยู่สำหรับขั้นตอนตรวจสอบความถูกต้องของแพ็ก +- เรียกใช้ `pnpm plugins:sync` หลังจากเพิ่มเวอร์ชันที่รากและก่อนติดแท็ก โดยจะ + อัปเดตเวอร์ชันแพ็กเกจ Plugin ที่เผยแพร่ได้, เมตาดาต้าความเข้ากันได้ของ peer/API ของ OpenClaw, + เมตาดาต้า build และสตับ changelog ของ Plugin ให้ตรงกับเวอร์ชันรีลีสหลัก + `pnpm plugins:sync:check` คือ guard รีลีสแบบไม่แก้ไขข้อมูล; + workflow เผยแพร่จะล้มเหลวก่อนมีการแก้ไข registry ใดๆ หากลืมขั้นตอนนี้ +- เรียกใช้ workflow แบบ manual `Full Release Validation` ก่อนอนุมัติรีลีสเพื่อ + เริ่ม test boxes ก่อนรีลีสทั้งหมดจาก entrypoint เดียว รับ branch, + tag หรือ full commit SHA, dispatch `CI` แบบ manual และ dispatch + `OpenClaw Release Checks` สำหรับ install smoke, package acceptance, ชุดทดสอบ + release-path ของ Docker, live/E2E, OpenWebUI, QA Lab parity, Matrix และ Telegram + lanes เมื่อใช้ `release_profile=full` และ `rerun_group=all` จะเรียกใช้ package + Telegram E2E กับอาร์ติแฟกต์ `release-package-under-test` จาก release + checks ด้วย ระบุ `npm_telegram_package_spec` หลังเผยแพร่เมื่อควรให้ Telegram E2E + เดียวกันพิสูจน์แพ็กเกจ npm ที่เผยแพร่แล้วด้วย ระบุ + `package_acceptance_package_spec` หลังเผยแพร่เมื่อ Package Acceptance + ควรเรียกใช้เมทริกซ์ package/update กับแพ็กเกจ npm ที่ส่งมอบแล้วแทนอาร์ติแฟกต์ที่ build จาก SHA ระบุ + `evidence_package_spec` เมื่อรายงานหลักฐานแบบ private ควรพิสูจน์ว่าการตรวจสอบความถูกต้อง + ตรงกับแพ็กเกจ npm ที่เผยแพร่แล้วโดยไม่บังคับใช้ Telegram E2E + ตัวอย่าง: + `gh workflow run full-release-validation.yml --ref main -f ref=release/YYYY.M.D` +- เรียกใช้ workflow แบบ manual `Package Acceptance` เมื่อคุณต้องการหลักฐาน side-channel + สำหรับตัวเลือกแพ็กเกจระหว่างที่งานรีลีสดำเนินต่อไป ใช้ `source=npm` สำหรับ + `openclaw@beta`, `openclaw@latest` หรือเวอร์ชันรีลีสที่ระบุแน่นอน; `source=ref` + เพื่อแพ็ก branch/tag/SHA `package_ref` ที่เชื่อถือได้ด้วย harness + `workflow_ref` ปัจจุบัน; `source=url` สำหรับ tarball HTTPS พร้อม SHA-256 + ที่จำเป็น; หรือ `source=artifact` สำหรับ tarball ที่อัปโหลดโดย GitHub + Actions run อื่น workflow จะแปลงตัวเลือกเป็น + `package-under-test`, ใช้ Docker E2E release scheduler ซ้ำกับ tarball นั้น + และสามารถเรียกใช้ Telegram QA กับ tarball เดียวกันด้วย + `telegram_mode=mock-openai` หรือ `telegram_mode=live-frontier` เมื่อ Docker + lanes ที่เลือกมี `published-upgrade-survivor` อาร์ติแฟกต์แพ็กเกจคือ + ตัวเลือก และ `published_upgrade_survivor_baseline` เลือก baseline ที่เผยแพร่แล้ว ตัวอย่าง: `gh workflow run package-acceptance.yml --ref main -f workflow_ref=main -f source=npm -f package_spec=openclaw@beta -f suite_profile=product -f published_upgrade_survivor_baseline=openclaw@2026.4.26 -f telegram_mode=mock-openai` โปรไฟล์ทั่วไป: - - `smoke`: lane สำหรับ install/channel/agent, gateway network และ config reload - - `package`: lane package/update/plugin ที่อิงอาร์ติแฟกต์โดยตรง โดยไม่มี OpenWebUI หรือ ClawHub live - - `product`: โปรไฟล์ package รวมถึงช่องทาง MCP, การล้างข้อมูล cron/subagent, OpenAI web search และ OpenWebUI - - `full`: ชิ้นส่วน Docker release-path พร้อม OpenWebUI - - `custom`: การเลือก `docker_lanes` แบบระบุชัดเจนสำหรับการ rerun เฉพาะจุด -- เรียกใช้ workflow แบบ manual `CI` โดยตรงเมื่อคุณต้องการเพียง coverage ของ CI ปกติแบบเต็มสำหรับ release candidate การ dispatch CI แบบ manual จะข้าม scoping ตามการเปลี่ยนแปลงและบังคับใช้ lane ของ Linux Node shard, bundled-plugin shard, channel contract, ความเข้ากันได้กับ Node 22, `check`, `check-additional`, build smoke, docs checks, Python skills, Windows, macOS, Android และ Control UI i18n + - `smoke`: lanes สำหรับ install/channel/agent, เครือข่าย Gateway และโหลด config ใหม่ + - `package`: lanes package/update/plugin ที่อิงอาร์ติแฟกต์โดยตรง โดยไม่มี OpenWebUI หรือ ClawHub แบบ live + - `product`: โปรไฟล์ package รวมกับช่อง MCP, cron/subagent cleanup, + OpenAI web search และ OpenWebUI + - `full`: ชิ้นส่วน release-path ของ Docker พร้อม OpenWebUI + - `custom`: การเลือก `docker_lanes` แบบเจาะจงสำหรับการ rerun ที่มุ่งเน้น +- เรียกใช้ workflow แบบ manual `CI` โดยตรงเมื่อคุณต้องการเพียงความครอบคลุมของ CI ปกติแบบเต็ม + สำหรับ release candidate การ dispatch CI แบบ manual จะข้ามการกำหนด scope ตามการเปลี่ยนแปลง + และบังคับใช้ Linux Node shards, bundled-plugin shards, channel + contracts, ความเข้ากันได้กับ Node 22, `check`, `check-additional`, build smoke, + docs checks, Python skills, Windows, macOS, Android และ Control UI i18n + lanes ตัวอย่าง: `gh workflow run ci.yml --ref release/YYYY.M.D` -- เรียกใช้ `pnpm qa:otel:smoke` เมื่อตรวจสอบ telemetry สำหรับการเผยแพร่ คำสั่งนี้ทดสอบ QA-lab ผ่านตัวรับ OTLP/HTTP ในเครื่อง และตรวจสอบชื่อ span ของ trace ที่ส่งออก, attribute ที่ถูกจำกัดขอบเขต และการ redact เนื้อหา/identifier โดยไม่ต้องใช้ Opik, Langfuse หรือตัวรวบรวมภายนอกอื่น -- เรียกใช้ `pnpm release:check` ก่อนทุกการเผยแพร่ที่ติดแท็ก -- เรียกใช้ `OpenClaw Release Publish` สำหรับลำดับการเผยแพร่ที่แก้ไขข้อมูลหลัง tag มีอยู่แล้ว Dispatch จาก `release/YYYY.M.D` (หรือ `main` เมื่อเผยแพร่ tag ที่เข้าถึงได้จาก main), ส่ง release tag และ `preflight_run_id` ของ OpenClaw npm ที่สำเร็จ และคง scope เผยแพร่ Plugin เริ่มต้น `all-publishable` ไว้ เว้นแต่คุณตั้งใจเรียกใช้การซ่อมแซมแบบเฉพาะจุด Workflow จะจัดลำดับการเผยแพร่ Plugin npm, การเผยแพร่ Plugin ClawHub และการเผยแพร่ OpenClaw npm เพื่อไม่ให้แพ็กเกจ core ถูกเผยแพร่ก่อน Plugin ที่ถูกแยกออกไปภายนอก -- ตอนนี้ release checks ทำงานใน workflow แบบ manual แยกต่างหาก: +- เรียกใช้ `pnpm qa:otel:smoke` เมื่อตรวจสอบ telemetry ของรีลีส โดยจะทดสอบ + QA-lab ผ่านตัวรับ OTLP/HTTP แบบ local และตรวจสอบชื่อ trace + span ที่ส่งออก, attributes ที่มีขอบเขต และการ redaction ของ content/identifier โดยไม่ต้องใช้ + Opik, Langfuse หรือตัวรวบรวมภายนอกอื่น +- เรียกใช้ `pnpm release:check` ก่อนรีลีสที่ติดแท็กทุกครั้ง +- เรียกใช้ `OpenClaw Release Publish` สำหรับลำดับการเผยแพร่ที่แก้ไขข้อมูลหลังจาก + มี tag แล้ว Dispatch จาก `release/YYYY.M.D` (หรือ `main` เมื่อเผยแพร่ tag + ที่เข้าถึงได้จาก main), ส่ง release tag และ OpenClaw npm + `preflight_run_id` ที่สำเร็จ และคงขอบเขตการเผยแพร่ Plugin ค่าเริ่มต้น + `all-publishable` ไว้ เว้นแต่คุณตั้งใจรันการซ่อมเฉพาะจุด workflow + จะจัดลำดับการเผยแพร่ npm ของ Plugin, การเผยแพร่ ClawHub ของ Plugin และการเผยแพร่ npm ของ OpenClaw + เพื่อไม่ให้แพ็กเกจหลักถูกเผยแพร่ก่อน Plugin ที่แยกออกไปภายนอก +- Release checks ตอนนี้รันใน workflow แบบ manual แยกต่างหาก: `OpenClaw Release Checks` -- `OpenClaw Release Checks` ยังเรียกใช้ lane QA Lab mock parity รวมถึงโปรไฟล์ Matrix live แบบเร็วและ lane Telegram QA ก่อนอนุมัติการเผยแพร่ Lane live ใช้ environment `qa-live-shared`; Telegram ยังใช้ lease ของ credential Convex CI ด้วย เรียกใช้ workflow แบบ manual `QA-Lab - All Lanes` พร้อม `matrix_profile=all` และ `matrix_shards=true` เมื่อคุณต้องการ inventory ของ Matrix transport, media และ E2EE แบบเต็มพร้อมกัน -- การตรวจสอบ runtime สำหรับการติดตั้งและอัปเกรดข้าม OS เป็นส่วนหนึ่งของ `OpenClaw Release Checks` และ `Full Release Validation` สาธารณะ ซึ่งเรียก reusable workflow `.github/workflows/openclaw-cross-os-release-checks-reusable.yml` โดยตรง -- การแยกนี้เป็นความตั้งใจ: รักษาเส้นทางเผยแพร่ npm จริงให้สั้น กำหนดผลได้แน่นอน และเน้นอาร์ติแฟกต์ ขณะที่การตรวจสอบ live ที่ช้ากว่าอยู่ใน lane ของตัวเอง เพื่อไม่ให้ถ่วงหรือบล็อกการเผยแพร่ -- release checks ที่มี secret ควรถูก dispatch ผ่าน `Full Release Validation` หรือจาก workflow ref `main`/release เพื่อให้ logic ของ workflow และ secret ยังถูกควบคุม -- `OpenClaw Release Checks` รับ branch, tag หรือ SHA ของ commit แบบเต็ม ตราบใดที่ commit ที่ resolve ได้สามารถเข้าถึงได้จาก branch ของ OpenClaw หรือ release tag -- การตรวจสอบก่อนเผยแพร่แบบ validation-only ของ `OpenClaw NPM Release` ยังรับ SHA ของ commit ใน workflow branch ปัจจุบันแบบเต็ม 40 อักขระได้โดยไม่ต้องมี tag ที่ push แล้ว -- เส้นทาง SHA นั้นใช้สำหรับการตรวจสอบเท่านั้น และไม่สามารถ promote เป็นการเผยแพร่จริงได้ -- ในโหมด SHA workflow จะสังเคราะห์ `v` เฉพาะสำหรับการตรวจสอบ metadata ของแพ็กเกจเท่านั้น; การเผยแพร่จริงยังต้องใช้ release tag จริง -- ทั้งสอง workflow คงเส้นทางเผยแพร่และ promote จริงไว้บน runner ที่โฮสต์โดย GitHub ขณะที่เส้นทางตรวจสอบแบบไม่แก้ไขข้อมูลสามารถใช้ runner Blacksmith Linux ที่ใหญ่กว่าได้ -- Workflow นั้นเรียกใช้ `OPENCLAW_LIVE_TEST=1 OPENCLAW_LIVE_CACHE_TEST=1 pnpm test:live:cache` โดยใช้ workflow secrets ทั้ง `OPENAI_API_KEY` และ `ANTHROPIC_API_KEY` -- การตรวจสอบก่อนเผยแพร่ npm ไม่รอ lane release checks ที่แยกต่างหากอีกต่อไป -- เรียกใช้ `RELEASE_TAG=vYYYY.M.D node --import tsx scripts/openclaw-npm-release-check.ts` (หรือ tag beta/correction ที่ตรงกัน) ก่อนอนุมัติ -- หลังเผยแพร่ npm ให้เรียกใช้ `node --import tsx scripts/openclaw-npm-postpublish-verify.ts YYYY.M.D` (หรือเวอร์ชัน beta/correction ที่ตรงกัน) เพื่อตรวจสอบเส้นทางติดตั้ง registry ที่เผยแพร่แล้วใน temp prefix ใหม่ -- หลังเผยแพร่ beta ให้เรียกใช้ `OPENCLAW_NPM_TELEGRAM_PACKAGE_SPEC=openclaw@YYYY.M.D-beta.N OPENCLAW_NPM_TELEGRAM_CREDENTIAL_SOURCE=convex OPENCLAW_NPM_TELEGRAM_CREDENTIAL_ROLE=ci pnpm test:docker:npm-telegram-live` เพื่อตรวจสอบ onboarding ของแพ็กเกจที่ติดตั้งแล้ว, การตั้งค่า Telegram และ Telegram E2E จริงกับแพ็กเกจ npm ที่เผยแพร่แล้ว โดยใช้พูล credential Telegram แบบ leased ที่ใช้ร่วมกัน maintainer ที่รันครั้งเดียวในเครื่องอาจละ Convex vars และส่ง credential env ทั้งสาม `OPENCLAW_QA_TELEGRAM_*` โดยตรงได้ -- Maintainer สามารถเรียกใช้การตรวจสอบหลังเผยแพร่เดียวกันจาก GitHub Actions ผ่าน workflow แบบ manual `NPM Telegram Beta E2E` ได้ Workflow นี้ตั้งใจให้เป็น manual-only และไม่ทำงานกับทุก merge -- ระบบอัตโนมัติการเผยแพร่ของ maintainer ตอนนี้ใช้ preflight-then-promote: - - การเผยแพร่ npm จริงต้องผ่าน `preflight_run_id` ของ npm ที่สำเร็จ - - การเผยแพร่ npm จริงต้องถูก dispatch จาก branch `main` หรือ `release/YYYY.M.D` เดียวกันกับ preflight run ที่สำเร็จ - - การเผยแพร่ npm แบบ stable มีค่าเริ่มต้นเป็น `beta` - - การเผยแพร่ npm แบบ stable สามารถ target `latest` อย่างชัดเจนผ่าน input ของ workflow - - การแก้ไข npm dist-tag ที่ใช้ token ตอนนี้อยู่ใน `openclaw/releases-private/.github/workflows/openclaw-npm-dist-tags.yml` ด้วยเหตุผลด้านความปลอดภัย เพราะ `npm dist-tag add` ยังต้องใช้ `NPM_TOKEN` ขณะที่ repo สาธารณะคงการเผยแพร่แบบ OIDC-only - - `macOS Release` สาธารณะเป็น validation-only; เมื่อ tag อยู่บน release branch เท่านั้นแต่ workflow ถูก dispatch จาก `main` ให้ตั้งค่า `public_release_branch=release/YYYY.M.D` - - การเผยแพร่ mac ส่วนตัวจริงต้องผ่าน `preflight_run_id` และ `validate_run_id` ของ mac ส่วนตัวที่สำเร็จ - - เส้นทางเผยแพร่จริง promote อาร์ติแฟกต์ที่เตรียมไว้แทนการ rebuild อีกครั้ง -- สำหรับการเผยแพร่แก้ไข stable เช่น `YYYY.M.D-N` ตัวตรวจสอบหลังเผยแพร่ยังตรวจเส้นทางอัปเกรดใน temp-prefix เดียวกันจาก `YYYY.M.D` ไปเป็น `YYYY.M.D-N` เพื่อไม่ให้ release correction ปล่อยให้การติดตั้ง global เก่ายังคงอยู่บน payload stable พื้นฐานโดยเงียบ ๆ -- การตรวจสอบก่อนเผยแพร่ npm จะ fail closed เว้นแต่ tarball จะมีทั้ง `dist/control-ui/index.html` และ payload `dist/control-ui/assets/` ที่ไม่ว่าง เพื่อไม่ให้เราส่งมอบ browser dashboard ว่างอีกครั้ง -- การตรวจสอบหลังเผยแพร่ยังตรวจว่า entrypoint ของ Plugin ที่เผยแพร่แล้วและ metadata ของแพ็กเกจมีอยู่ใน layout ของ registry ที่ติดตั้งแล้ว การเผยแพร่ที่ขาด payload runtime ของ Plugin จะทำให้ตัวตรวจสอบ postpublish ล้มเหลวและไม่สามารถ promote เป็น `latest` ได้ -- `pnpm test:install:smoke` ยังบังคับใช้งบประมาณ `unpackedSize` ของ npm pack กับ tarball อัปเดต candidate ด้วย ดังนั้น installer e2e จะจับ pack bloat ที่ไม่ตั้งใจก่อนเส้นทางเผยแพร่ release -- หากงานเผยแพร่แตะการวางแผน CI, manifest timing ของ extension หรือเมทริกซ์ทดสอบ extension ให้สร้างใหม่และทบทวนผลลัพธ์เมทริกซ์ `plugin-prerelease-extension-shard` ที่ planner เป็นเจ้าของจาก `.github/workflows/plugin-prerelease.yml` ก่อนอนุมัติ เพื่อไม่ให้ release notes อธิบาย layout CI ที่ล้าสมัย -- ความพร้อมของการเผยแพร่ macOS แบบ stable ยังรวมถึงพื้นผิว updater: - - GitHub release ต้องลงเอยด้วย `.zip`, `.dmg` และ `.dSYM.zip` ที่บรรจุแพ็กเกจแล้ว - - `appcast.xml` บน `main` ต้องชี้ไปยัง zip stable ใหม่หลังเผยแพร่ - - แอปที่บรรจุแพ็กเกจแล้วต้องคง bundle id ที่ไม่ใช่ debug, URL feed ของ Sparkle ที่ไม่ว่าง และ `CFBundleVersion` ที่เท่ากับหรือสูงกว่า build floor มาตรฐานของ Sparkle สำหรับเวอร์ชันเผยแพร่นั้น +- `OpenClaw Release Checks` ยังเรียกใช้ QA Lab mock parity lane พร้อมโปรไฟล์ Matrix + แบบ live ที่เร็วและ Telegram QA lane ก่อนอนุมัติรีลีสด้วย live + lanes ใช้ environment `qa-live-shared`; Telegram ยังใช้ leases ข้อมูลรับรอง Convex CI + ด้วย เรียกใช้ workflow แบบ manual `QA-Lab - All Lanes` ด้วย + `matrix_profile=all` และ `matrix_shards=true` เมื่อคุณต้องการ inventory ของ Matrix + transport, media และ E2EE แบบเต็มในแบบขนาน +- การตรวจสอบ runtime สำหรับการติดตั้งและอัปเกรดข้าม OS เป็นส่วนหนึ่งของ + `OpenClaw Release Checks` และ `Full Release Validation` สาธารณะ ซึ่งเรียกใช้ + reusable workflow + `.github/workflows/openclaw-cross-os-release-checks-reusable.yml` โดยตรง +- การแยกนี้เป็นความตั้งใจ: รักษาเส้นทางรีลีส npm จริงให้สั้น + deterministic และมุ่งเน้นอาร์ติแฟกต์ ขณะที่การตรวจแบบ live ที่ช้ากว่าอยู่ใน lane + ของตัวเอง เพื่อไม่ให้หยุดชะงักหรือบล็อกการเผยแพร่ +- Release checks ที่มี secret ควรถูก dispatch ผ่าน `Full Release +Validation` หรือจาก workflow ref ของ `main`/release เพื่อให้ logic ของ workflow และ + secrets ยังอยู่ภายใต้การควบคุม +- `OpenClaw Release Checks` รับ branch, tag หรือ full commit SHA ตราบใดที่ + commit ที่ resolve ได้เข้าถึงได้จาก branch ของ OpenClaw หรือ release tag +- preflight แบบ validation-only ของ `OpenClaw NPM Release` ยังรับ + full 40-character workflow-branch commit SHA ปัจจุบันโดยไม่ต้องมี pushed tag +- เส้นทาง SHA นั้นเป็น validation-only และไม่สามารถเลื่อนระดับเป็นการเผยแพร่จริงได้ +- ในโหมด SHA workflow จะสร้าง `v` เฉพาะสำหรับการตรวจเมตาดาต้า + แพ็กเกจเท่านั้น; การเผยแพร่จริงยังต้องใช้ release tag จริง +- workflow ทั้งสองคงเส้นทางเผยแพร่และ promotion จริงไว้บน GitHub-hosted + runners ขณะที่เส้นทาง validation แบบไม่แก้ไขข้อมูลสามารถใช้ Blacksmith Linux runners + ที่ใหญ่กว่าได้ +- workflow นั้นเรียกใช้ + `OPENCLAW_LIVE_TEST=1 OPENCLAW_LIVE_CACHE_TEST=1 pnpm test:live:cache` + โดยใช้ workflow secrets ทั้ง `OPENAI_API_KEY` และ `ANTHROPIC_API_KEY` +- preflight รีลีส npm จะไม่รอ release checks lane แยกอีกต่อไป +- เรียกใช้ `RELEASE_TAG=vYYYY.M.D node --import tsx scripts/openclaw-npm-release-check.ts` + (หรือ tag beta/correction ที่ตรงกัน) ก่อนอนุมัติ +- หลังจากเผยแพร่ npm ให้เรียกใช้ + `node --import tsx scripts/openclaw-npm-postpublish-verify.ts YYYY.M.D` + (หรือเวอร์ชัน beta/correction ที่ตรงกัน) เพื่อตรวจสอบเส้นทางการติดตั้ง registry + ที่เผยแพร่แล้วใน prefix ชั่วคราวใหม่ +- หลังเผยแพร่ beta ให้เรียกใช้ `OPENCLAW_NPM_TELEGRAM_PACKAGE_SPEC=openclaw@YYYY.M.D-beta.N OPENCLAW_NPM_TELEGRAM_CREDENTIAL_SOURCE=convex OPENCLAW_NPM_TELEGRAM_CREDENTIAL_ROLE=ci pnpm test:docker:npm-telegram-live` + เพื่อตรวจสอบ onboarding ของแพ็กเกจที่ติดตั้งแล้ว, การตั้งค่า Telegram และ Telegram E2E จริง + กับแพ็กเกจ npm ที่เผยแพร่แล้วโดยใช้พูลข้อมูลรับรอง Telegram แบบ leased ที่ใช้ร่วมกัน + การรันเฉพาะกิจบนเครื่อง maintainer แบบ local อาจละเว้น Convex vars และส่ง credentials env + `OPENCLAW_QA_TELEGRAM_*` ทั้งสามโดยตรงได้ +- หากต้องการรัน post-publish beta smoke แบบเต็มจากเครื่อง maintainer ให้ใช้ `pnpm release:beta-smoke -- --beta betaN` helper จะรันการตรวจสอบ Parallels npm update/fresh-target, dispatch `NPM Telegram Beta E2E`, poll workflow run ที่ระบุแน่นอน, ดาวน์โหลดอาร์ติแฟกต์ และพิมพ์รายงาน Telegram +- Maintainers สามารถรันการตรวจ post-publish เดียวกันจาก GitHub Actions ผ่าน + workflow แบบ manual `NPM Telegram Beta E2E` ได้ โดยตั้งใจให้เป็น manual-only และ + ไม่รันทุกครั้งที่ merge +- ระบบอัตโนมัติสำหรับรีลีสของ maintainer ตอนนี้ใช้ preflight-then-promote: + - การเผยแพร่ npm จริงต้องผ่าน npm `preflight_run_id` ที่สำเร็จ + - การเผยแพร่ npm จริงต้องถูก dispatch จาก branch `main` หรือ + `release/YYYY.M.D` เดียวกับ preflight run ที่สำเร็จ + - รีลีส npm แบบ stable ค่าเริ่มต้นคือ `beta` + - การเผยแพร่ npm แบบ stable สามารถกำหนดเป้าหมาย `latest` ได้อย่างชัดเจนผ่าน workflow input + - การแก้ไข npm dist-tag ด้วย token ตอนนี้อยู่ใน + `openclaw/releases-private/.github/workflows/openclaw-npm-dist-tags.yml` + เพื่อความปลอดภัย เพราะ `npm dist-tag add` ยังต้องใช้ `NPM_TOKEN` ขณะที่ + public repo คงการเผยแพร่แบบ OIDC-only + - `macOS Release` สาธารณะเป็น validation-only; เมื่อ tag อยู่เฉพาะบน + release branch แต่ workflow ถูก dispatch จาก `main` ให้ตั้งค่า + `public_release_branch=release/YYYY.M.D` + - การเผยแพร่ mac แบบ private จริงต้องผ่าน private mac + `preflight_run_id` และ `validate_run_id` ที่สำเร็จ + - เส้นทางเผยแพร่จริงจะ promote อาร์ติแฟกต์ที่เตรียมไว้แทนการ rebuild + อีกครั้ง +- สำหรับรีลีส correction แบบ stable เช่น `YYYY.M.D-N` ตัวตรวจสอบ post-publish + จะตรวจเส้นทางอัปเกรด temp-prefix เดียวกันจาก `YYYY.M.D` เป็น `YYYY.M.D-N` + ด้วย เพื่อไม่ให้ release corrections ปล่อยให้การติดตั้ง global รุ่นเก่าอยู่บน payload + stable ฐานอย่างเงียบๆ +- preflight รีลีส npm จะ fail closed เว้นแต่ tarball จะมีทั้ง + `dist/control-ui/index.html` และ payload `dist/control-ui/assets/` ที่ไม่ว่าง + เพื่อไม่ให้เราส่ง dashboard เบราว์เซอร์ที่ว่างเปล่าอีก +- การตรวจสอบ post-publish ยังตรวจว่า entrypoints ของ Plugin ที่เผยแพร่แล้วและ + เมตาดาต้าแพ็กเกจมีอยู่ใน layout registry ที่ติดตั้งแล้ว รีลีสที่ส่ง runtime payloads ของ Plugin + ขาดหายจะทำให้ตัวตรวจสอบ postpublish ล้มเหลว และ + ไม่สามารถ promote เป็น `latest` ได้ +- `pnpm test:install:smoke` ยังบังคับใช้งบประมาณ `unpackedSize` ของ npm pack กับ + candidate update tarball ดังนั้น installer e2e จะจับ pack bloat ที่ไม่ได้ตั้งใจ + ได้ก่อนเส้นทางเผยแพร่รีลีส +- หากงานรีลีสแตะการวางแผน CI, manifests เวลา extension หรือ + เมทริกซ์การทดสอบ extension ให้สร้างใหม่และทบทวน outputs ของเมทริกซ์ + `plugin-prerelease-extension-shard` ที่ planner เป็นเจ้าของจาก + `.github/workflows/plugin-prerelease.yml` ก่อนอนุมัติ เพื่อให้ release notes ไม่ + อธิบาย layout CI ที่ล้าสมัย +- ความพร้อมของรีลีส macOS แบบ stable ยังรวมถึง surfaces ของ updater: + - GitHub release ต้องลงเอยด้วย `.zip`, `.dmg` และ `.dSYM.zip` ที่แพ็กแล้ว + - `appcast.xml` บน `main` ต้องชี้ไปที่ zip แบบ stable ใหม่หลังเผยแพร่ + - แอปที่แพ็กแล้วต้องคง bundle id ที่ไม่ใช่ debug, URL feed Sparkle ที่ไม่ว่าง + และ `CFBundleVersion` ที่เท่ากับหรือสูงกว่า canonical Sparkle build floor + สำหรับเวอร์ชันรีลีสนั้น -## กล่องทดสอบการเผยแพร่ +## กล่องทดสอบรีลีส -`Full Release Validation` คือวิธีที่ operator ใช้เริ่มการทดสอบก่อนเผยแพร่ทั้งหมดจาก entrypoint เดียว สำหรับหลักฐาน commit ที่ pin ไว้บน branch ที่เคลื่อนไหวเร็ว ให้ใช้ helper เพื่อให้ workflow ลูกทุกตัวทำงานจาก branch ชั่วคราวที่ตรึงไว้กับ SHA เป้าหมาย: +`Full Release Validation` คือวิธีที่ operators เริ่มการทดสอบก่อนรีลีสทั้งหมดจาก +entrypoint เดียว สำหรับหลักฐาน commit ที่ pin ไว้บน branch ที่เปลี่ยนเร็ว ให้ใช้ +helper เพื่อให้ workflow ลูกทุกตัวรันจาก branch ชั่วคราวที่ตรึงไว้กับ target +SHA: ```bash pnpm ci:full-release --sha ``` -Helper จะ push `release-ci/-...`, dispatch `Full Release Validation` จาก branch นั้นด้วย `ref=`, ตรวจสอบว่า `headSha` ของ workflow ลูกทุกตัวตรงกับเป้าหมาย แล้วลบ branch ชั่วคราว วิธีนี้หลีกเลี่ยงการพิสูจน์ run ลูกของ `main` ที่ใหม่กว่าโดยไม่ตั้งใจ +helper จะ push `release-ci/-...`, dispatch `Full Release Validation` +จาก branch นั้นด้วย `ref=`, ตรวจสอบว่า `headSha` ของ workflow ลูกทุกตัว +ตรงกับ target จากนั้นลบ branch ชั่วคราว วิธีนี้หลีกเลี่ยงการพิสูจน์ child run ของ +`main` ที่ใหม่กว่าโดยไม่ตั้งใจ -สำหรับการตรวจสอบ release branch หรือ tag ให้เรียกใช้จาก workflow ref `main` ที่เชื่อถือได้และส่ง release branch หรือ tag เป็น `ref`: +สำหรับการตรวจสอบ release branch หรือ tag ให้รันจาก workflow ref `main` ที่เชื่อถือได้ +และส่ง release branch หรือ tag เป็น `ref`: ```bash gh workflow run full-release-validation.yml \ @@ -179,48 +280,48 @@ gh workflow run full-release-validation.yml \ -f evidence_package_spec=openclaw@YYYY.M.D-beta.N ``` -เวิร์กโฟลว์จะ resolve target ref, dispatch `CI` แบบ manual ด้วย +เวิร์กโฟลว์จะ resolve ref เป้าหมาย, dispatch `CI` แบบ manual ด้วย `target_ref=`, dispatch `OpenClaw Release Checks`, เตรียม artifact -หลัก `release-package-under-test` สำหรับการตรวจสอบที่เกี่ยวข้องกับแพ็กเกจ และ -dispatch package Telegram E2E แบบ standalone เมื่อ `release_profile=full` พร้อม -`rerun_group=all` หรือเมื่อมีการตั้งค่า `npm_telegram_package_spec` จากนั้น `OpenClaw Release -Checks` จะกระจายไปยัง install smoke, cross-OS release checks, live/E2E Docker -release-path coverage, Package Acceptance พร้อม Telegram package QA, QA Lab -parity, live Matrix และ live Telegram การรันแบบเต็มจะยอมรับได้ก็ต่อเมื่อ -สรุป `Full Release Validation` -แสดงว่า `normal_ci` และ `release_checks` สำเร็จ ในโหมด full/all -child `npm_telegram` ต้องสำเร็จด้วย; นอก full/all จะถูกข้าม -เว้นแต่จะมีการระบุ `npm_telegram_package_spec` ที่เผยแพร่แล้ว สรุป verifier -สุดท้ายมีตารางงานที่ช้าที่สุดสำหรับ child run แต่ละรายการ เพื่อให้ผู้จัดการ release -เห็น critical path ปัจจุบันได้โดยไม่ต้องดาวน์โหลด logs -ดู [การตรวจสอบ release แบบเต็ม](/th/reference/full-release-validation) สำหรับ -stage matrix ฉบับครบถ้วน, ชื่องาน workflow ที่แน่นอน, ความแตกต่างระหว่างโปรไฟล์ stable กับ full, -artifacts และ handle สำหรับ rerun แบบเฉพาะจุด -Child workflows จะถูก dispatch จาก trusted ref ที่รัน `Full Release -Validation` โดยปกติคือ `--ref main` แม้ target `ref` จะชี้ไปที่ -release branch หรือ tag ที่เก่ากว่า ไม่มี input workflow-ref แยกต่างหากสำหรับ Full Release Validation; -ให้เลือก trusted harness โดยเลือก workflow run ref -อย่าใช้ `--ref main -f ref=` สำหรับหลักฐาน commit แบบแน่นอนบน `main` ที่เคลื่อนที่อยู่; -raw commit SHA ไม่สามารถเป็น workflow dispatch refs ได้ ดังนั้นให้ใช้ -`pnpm ci:full-release --sha ` เพื่อสร้าง pinned temporary branch +หลัก `release-package-under-test` สำหรับการตรวจสอบฝั่งแพ็กเกจ และ dispatch +Telegram E2E แบบแพ็กเกจ standalone เมื่อ `release_profile=full` พร้อม +`rerun_group=all` หรือเมื่อมีการตั้งค่า `npm_telegram_package_spec` จากนั้น +`OpenClaw Release Checks` จะ fan out ไปยัง install smoke, การตรวจสอบรีลีสข้าม OS, +ความครอบคลุม live/E2E Docker ตาม release path, Package Acceptance พร้อม QA +แพ็กเกจ Telegram, QA Lab parity, live Matrix และ live Telegram การรันแบบเต็มจะ +ยอมรับได้ก็ต่อเมื่อสรุป `Full Release Validation` แสดงว่า `normal_ci` และ +`release_checks` สำเร็จแล้วเท่านั้น ในโหมด full/all child `npm_telegram` ต้อง +สำเร็จด้วย นอก full/all จะถูกข้าม เว้นแต่จะมีการระบุ +`npm_telegram_package_spec` ที่เผยแพร่แล้ว สรุป verifier สุดท้ายมีตารางงานที่ +ช้าที่สุดสำหรับแต่ละ child run เพื่อให้ผู้จัดการรีลีสเห็น critical path ปัจจุบัน +ได้โดยไม่ต้องดาวน์โหลด log +ดู [การตรวจสอบรีลีสแบบเต็ม](/th/reference/full-release-validation) สำหรับ stage +matrix ฉบับสมบูรณ์, ชื่องาน workflow ที่แน่นอน, ความแตกต่างระหว่างโปรไฟล์ stable +กับ full, artifacts และ handle สำหรับ rerun แบบเจาะจง +Child workflows จะถูก dispatch จาก ref ที่เชื่อถือได้ซึ่งรัน `Full Release +Validation` โดยปกติคือ `--ref main` แม้ว่า `ref` เป้าหมายจะชี้ไปที่ release +branch หรือ tag ที่เก่ากว่าก็ตาม ไม่มี input workflow-ref แยกต่างหากสำหรับ Full +Release Validation ให้เลือก harness ที่เชื่อถือได้โดยเลือก ref ของ workflow run +อย่าใช้ `--ref main -f ref=` เพื่อพิสูจน์ commit แบบเจาะจงบน `main` ที่เลื่อนไป +เรื่อย ๆ เพราะ raw commit SHA ไม่สามารถเป็น workflow dispatch ref ได้ ดังนั้นให้ใช้ +`pnpm ci:full-release --sha ` เพื่อสร้าง branch ชั่วคราวที่ pin ไว้ ใช้ `release_profile` เพื่อเลือกขอบเขต live/provider: -- `minimum`: เส้นทาง OpenAI/core live และ Docker ที่สำคัญต่อ release และเร็วที่สุด -- `stable`: minimum พร้อม coverage ของ provider/backend ที่ stable สำหรับอนุมัติ release -- `full`: stable พร้อม coverage กว้างของ advisory provider/media +- `minimum`: เส้นทาง live และ Docker ที่สำคัญต่อรีลีสของ OpenAI/core ที่เร็วที่สุด +- `stable`: minimum พร้อมความครอบคลุม provider/backend แบบ stable สำหรับการอนุมัติรีลีส +- `full`: stable พร้อมความครอบคลุม provider/media เชิง advisory ที่กว้างขึ้น -`OpenClaw Release Checks` ใช้ trusted workflow ref เพื่อ resolve target -ref หนึ่งครั้งเป็น `release-package-under-test` และ reuse artifact นั้นทั้งใน -release-path Docker checks และ Package Acceptance วิธีนี้ทำให้ทุก -box ที่เกี่ยวข้องกับแพ็กเกจใช้ bytes ชุดเดียวกันและหลีกเลี่ยงการ build แพ็กเกจซ้ำ +`OpenClaw Release Checks` ใช้ workflow ref ที่เชื่อถือได้เพื่อ resolve ref เป้าหมาย +หนึ่งครั้งเป็น `release-package-under-test` และนำ artifact นั้นกลับมาใช้ทั้งในการ +ตรวจสอบ Docker ตาม release path และ Package Acceptance สิ่งนี้ทำให้กล่องฝั่ง +แพ็กเกจทั้งหมดอยู่บน bytes เดียวกัน และหลีกเลี่ยงการ build แพ็กเกจซ้ำ cross-OS OpenAI install smoke ใช้ `OPENCLAW_CROSS_OS_OPENAI_MODEL` เมื่อมีการตั้งค่า -repo/org variable มิฉะนั้นจะใช้ `openai/gpt-5.4` เพราะ lane นี้กำลัง -พิสูจน์ package install, onboarding, gateway startup และ live agent turn หนึ่งครั้ง -ไม่ใช่การ benchmark default model ที่ช้าที่สุด ส่วน live provider -matrix ที่กว้างกว่ายังคงเป็นที่สำหรับ coverage เฉพาะ model +ตัวแปร repo/org ไม่เช่นนั้นจะใช้ `openai/gpt-5.4` เพราะ lane นี้พิสูจน์การติดตั้ง +แพ็กเกจ, onboarding, การเริ่มต้น Gateway และ agent turn แบบ live หนึ่งครั้ง +มากกว่าการ benchmark โมเดล default ที่ช้าที่สุด ส่วน live provider matrix ที่กว้างกว่า +ยังคงเป็นที่สำหรับความครอบคลุมเฉพาะโมเดล -ใช้ variants เหล่านี้ตาม stage ของ release: +ใช้ variant เหล่านี้ตาม stage ของรีลีส: ```bash # Validate an unpublished release candidate branch. @@ -250,41 +351,41 @@ gh workflow run full-release-validation.yml \ -f npm_telegram_provider_mode=mock-openai ``` -อย่าใช้ umbrella แบบเต็มเป็นการ rerun ครั้งแรกหลังแก้แบบเฉพาะจุด หาก box หนึ่ง -ล้มเหลว ให้ใช้ child workflow, งาน, Docker lane, package profile, model -provider หรือ QA lane ที่ล้มเหลวสำหรับหลักฐานถัดไป รัน umbrella แบบเต็มอีกครั้งก็ต่อเมื่อ -การแก้เปลี่ยน release orchestration ที่ใช้ร่วมกัน หรือทำให้หลักฐาน all-box ก่อนหน้า -ล้าสมัย verifier สุดท้ายของ umbrella จะตรวจซ้ำ workflow run -ids ของ child ที่บันทึกไว้ ดังนั้นหลังจาก child workflow ถูก rerun สำเร็จแล้ว ให้ rerun เฉพาะงานหลัก +อย่าใช้ umbrella แบบเต็มเป็น rerun แรกหลังจากการแก้ไขแบบเจาะจง หากกล่องหนึ่งล้มเหลว +ให้ใช้ child workflow, job, Docker lane, package profile, model provider หรือ QA +lane ที่ล้มเหลวสำหรับ proof ถัดไป รัน umbrella แบบเต็มอีกครั้งเฉพาะเมื่อการแก้ไข +เปลี่ยน release orchestration ที่ใช้ร่วมกัน หรือทำให้ evidence แบบทุกกล่องก่อนหน้า +ล้าสมัย final verifier ของ umbrella จะตรวจซ้ำ workflow run id ของ child ที่บันทึกไว้ +ดังนั้นหลังจาก rerun child workflow สำเร็จแล้ว ให้ rerun เฉพาะ parent job `Verify full validation` ที่ล้มเหลว สำหรับการกู้คืนแบบมีขอบเขต ให้ส่ง `rerun_group` ไปยัง umbrella `all` คือการรัน -release-candidate จริง, `ci` รันเฉพาะ child ของ CI ปกติ, `plugin-prerelease` -รันเฉพาะ child ของ Plugin เฉพาะ release, `release-checks` รัน release -box ทุกตัว และ release groups ที่แคบกว่าคือ `install-smoke`, `cross-os`, -`live-e2e`, `package`, `qa`, `qa-parity`, `qa-live` และ `npm-telegram` -การ rerun `npm-telegram` แบบเฉพาะจุดต้องมี `npm_telegram_package_spec`; การรัน full/all -ที่มี `release_profile=full` ใช้ release-checks package artifact +release-candidate จริง, `ci` รันเฉพาะ normal CI child, `plugin-prerelease` รันเฉพาะ +plugin child สำหรับรีลีสเท่านั้น, `release-checks` รันทุก release box และกลุ่มรีลีส +ที่แคบกว่าคือ `install-smoke`, `cross-os`, `live-e2e`, `package`, `qa`, +`qa-parity`, `qa-live` และ `npm-telegram` การ rerun `npm-telegram` แบบเจาะจงต้องมี +`npm_telegram_package_spec`; การรัน full/all ด้วย `release_profile=full` ใช้ package +artifact ของ release-checks ### Vitest -Vitest box คือ child workflow `CI` แบบ manual Manual CI ตั้งใจ -ข้าม changed scoping และบังคับ test graph ปกติสำหรับ release -candidate: Linux Node shards, bundled-plugin shards, channel contracts, Node 22 -compatibility, `check`, `check-additional`, build smoke, docs checks, Python -skills, Windows, macOS, Android และ Control UI i18n +กล่อง Vitest คือ child workflow `CI` แบบ manual Manual CI ตั้งใจ bypass changed +scoping และบังคับใช้กราฟทดสอบปกติสำหรับ release candidate: Linux Node shards, +bundled-plugin shards, channel contracts, ความเข้ากันได้กับ Node 22, `check`, +`check-additional`, build smoke, docs checks, Python skills, Windows, macOS, +Android และ Control UI i18n -ใช้ box นี้เพื่อตอบว่า "source tree ผ่านชุดทดสอบปกติแบบเต็มหรือไม่?" -นี่ไม่เหมือนกับการตรวจสอบผลิตภัณฑ์ตาม release-path หลักฐานที่ควรเก็บ: +ใช้กล่องนี้เพื่อตอบว่า "source tree ผ่านชุดทดสอบปกติแบบเต็มหรือไม่?" +มันไม่เหมือนกับการตรวจสอบผลิตภัณฑ์ตาม release path หลักฐานที่ควรเก็บ: -- สรุป `Full Release Validation` ที่แสดง URL ของ `CI` run ที่ถูก dispatch -- `CI` run เป็นสีเขียวบน target SHA ที่แน่นอน -- ชื่อ shard ที่ล้มเหลวหรือช้าจากงาน CI เมื่อตรวจสอบ regression -- Vitest timing artifacts เช่น `.artifacts/vitest-shard-timings.json` เมื่อ +- สรุป `Full Release Validation` ที่แสดง URL ของ `CI` run ที่ dispatch แล้ว +- `CI` run เป็นสีเขียวบน SHA เป้าหมายที่แน่นอน +- ชื่อ shard ที่ล้มเหลวหรือช้าจากงาน CI เมื่อสืบสวน regression +- timing artifacts ของ Vitest เช่น `.artifacts/vitest-shard-timings.json` เมื่อ run ต้องการการวิเคราะห์ประสิทธิภาพ -รัน manual CI โดยตรงเฉพาะเมื่อ release ต้องการ CI ปกติที่ deterministic แต่ -ไม่ต้องใช้ Docker, QA Lab, live, cross-OS หรือ package boxes: +รัน manual CI โดยตรงเฉพาะเมื่อรีลีสต้องการ normal CI แบบ deterministic แต่ไม่ต้องการ +กล่อง Docker, QA Lab, live, cross-OS หรือ package: ```bash gh workflow run ci.yml --ref main -f target_ref=release/YYYY.M.D @@ -292,111 +393,110 @@ gh workflow run ci.yml --ref main -f target_ref=release/YYYY.M.D ### Docker -Docker box อยู่ใน `OpenClaw Release Checks` ผ่าน +กล่อง Docker อยู่ใน `OpenClaw Release Checks` ผ่าน `openclaw-live-and-e2e-checks-reusable.yml` รวมถึง workflow `install-smoke` -แบบ release-mode โดยตรวจสอบ release candidate ผ่านสภาพแวดล้อม Docker -แบบ packaged แทนที่จะใช้เฉพาะการทดสอบระดับ source +ในโหมดรีลีส มันตรวจสอบ release candidate ผ่านสภาพแวดล้อม Docker แบบแพ็กเกจ +แทนที่จะเป็นเฉพาะการทดสอบระดับซอร์ส -Release Docker coverage รวมถึง: +ความครอบคลุม Docker ของรีลีสประกอบด้วย: -- install smoke แบบเต็มโดยเปิดใช้ Bun global install smoke ที่ช้า -- การเตรียม/reuse root Dockerfile smoke image ตาม target SHA พร้อมงาน QR, - root/gateway และ installer/Bun smoke ที่รันเป็น install-smoke shards แยกกัน -- repository E2E lanes -- release-path Docker chunks: `core`, `package-update-openai`, +- full install smoke พร้อมเปิดใช้ slow Bun global install smoke +- การเตรียม/นำ smoke image ของ root Dockerfile กลับมาใช้ตาม SHA เป้าหมาย โดยมีงาน QR, + root/gateway และ installer/Bun smoke รันเป็น install-smoke shards แยกกัน +- lane E2E ของ repository +- chunk Docker ตาม release path: `core`, `package-update-openai`, `package-update-anthropic`, `package-update-core`, `plugins-runtime-plugins`, `plugins-runtime-services`, `plugins-runtime-install-a`, `plugins-runtime-install-b`, `plugins-runtime-install-c`, `plugins-runtime-install-d`, `plugins-runtime-install-e`, `plugins-runtime-install-f`, `plugins-runtime-install-g` และ `plugins-runtime-install-h` -- OpenWebUI coverage ภายใน chunk `plugins-runtime-services` เมื่อมีการร้องขอ -- lane ติดตั้ง/ถอนติดตั้ง bundled plugin แบบแยก +- ความครอบคลุม OpenWebUI ภายใน chunk `plugins-runtime-services` เมื่อมีการร้องขอ +- lane install/uninstall ของ bundled Plugin ที่ split แล้ว `bundled-plugin-install-uninstall-0` ถึง `bundled-plugin-install-uninstall-23` -- ชุด live/E2E provider และ Docker live model coverage เมื่อ release checks +- ชุด provider live/E2E และความครอบคลุมโมเดล Docker live เมื่อ release checks รวม live suites ใช้ Docker artifacts ก่อน rerun release-path scheduler อัปโหลด -`.artifacts/docker-tests/` พร้อม lane logs, `summary.json`, `failures.json`, -phase timings, scheduler plan JSON และคำสั่ง rerun สำหรับการกู้คืนแบบเฉพาะจุด -ให้ใช้ `docker_lanes=` บน workflow live/E2E แบบ reusable แทน -การ rerun release chunks ทั้งหมด คำสั่ง rerun ที่สร้างขึ้นจะรวม -`package_artifact_run_id` ก่อนหน้าและ prepared Docker image inputs เมื่อมี เพื่อให้ -lane ที่ล้มเหลวสามารถ reuse tarball และ GHCR images ชุดเดียวกันได้ +`.artifacts/docker-tests/` พร้อม log ของ lane, `summary.json`, `failures.json`, +phase timings, scheduler plan JSON และคำสั่ง rerun สำหรับการกู้คืนแบบเจาะจง ให้ใช้ +`docker_lanes=` บน reusable live/E2E workflow แทนการ rerun release +chunks ทั้งหมด คำสั่ง rerun ที่สร้างขึ้นจะรวม `package_artifact_run_id` ก่อนหน้าและ +input ของ Docker image ที่เตรียมไว้เมื่อมี เพื่อให้ lane ที่ล้มเหลวสามารถใช้ tarball +และ GHCR images เดิมซ้ำได้ ### QA Lab -QA Lab box เป็นส่วนหนึ่งของ `OpenClaw Release Checks` เช่นกัน เป็น gate ด้าน -พฤติกรรม agentic และระดับ channel สำหรับ release ซึ่งแยกจาก Vitest และกลไกแพ็กเกจ -ของ Docker +กล่อง QA Lab เป็นส่วนหนึ่งของ `OpenClaw Release Checks` เช่นกัน มันคือ release gate +ด้านพฤติกรรม agentic และระดับ channel แยกจากกลไกแพ็กเกจของ Vitest และ Docker -Release QA Lab coverage รวมถึง: +ความครอบคลุม QA Lab ของรีลีสประกอบด้วย: -- mock parity lane ที่เปรียบเทียบ OpenAI candidate lane กับ baseline Opus 4.6 +- mock parity lane ที่เปรียบเทียบ lane candidate ของ OpenAI กับ baseline Opus 4.6 โดยใช้ agentic parity pack -- fast live Matrix QA profile ที่ใช้ environment `qa-live-shared` -- live Telegram QA lane ที่ใช้ Convex CI credential leases -- `pnpm qa:otel:smoke` เมื่อ release telemetry ต้องการหลักฐาน local ที่ชัดเจน +- โปรไฟล์ fast live Matrix QA ที่ใช้ environment `qa-live-shared` +- live Telegram QA lane ที่ใช้ credential lease ของ Convex CI +- `pnpm qa:otel:smoke` เมื่อ release telemetry ต้องการ local proof ที่ชัดเจน -ใช้ box นี้เพื่อตอบว่า "release ทำงานถูกต้องในสถานการณ์ QA และ -live channel flows หรือไม่?" เก็บ artifact URLs สำหรับ parity, Matrix และ Telegram -lanes เมื่ออนุมัติ release Full Matrix coverage ยังมีให้ใช้งานเป็น -QA-Lab run แบบ manual sharded ไม่ใช่ lane สำคัญต่อ release ตามค่าเริ่มต้น +ใช้กล่องนี้เพื่อตอบว่า "รีลีสทำงานถูกต้องในสถานการณ์ QA และ flow ของ live channel +หรือไม่?" เก็บ URL artifact สำหรับ lane parity, Matrix และ Telegram เมื่ออนุมัติรีลีส +ความครอบคลุม Matrix แบบเต็มยังมีให้เป็น QA-Lab run แบบ sharded manual แทนที่จะเป็น +lane สำคัญต่อรีลีสตาม default -### แพ็กเกจ +### Package -Package box คือ installable-product gate ซึ่งรองรับโดย +กล่อง Package คือ gate สำหรับผลิตภัณฑ์ที่ติดตั้งได้ รองรับโดย `Package Acceptance` และ resolver -`scripts/resolve-openclaw-package-candidate.mjs` resolver จะ normalize -candidate ให้เป็น tarball `package-under-test` ที่ Docker E2E ใช้, ตรวจสอบ -package inventory, บันทึก package version และ SHA-256 และแยก workflow harness ref -ออกจาก package source ref +`scripts/resolve-openclaw-package-candidate.mjs` resolver จะ normalize candidate +เป็น tarball `package-under-test` ที่ Docker E2E ใช้, validate package inventory, +บันทึก version และ SHA-256 ของแพ็กเกจ และแยก workflow harness ref ออกจาก package +source ref แหล่ง candidate ที่รองรับ: -- `source=npm`: `openclaw@beta`, `openclaw@latest` หรือเวอร์ชัน OpenClaw release ที่แน่นอน -- `source=ref`: pack branch, tag หรือ full commit SHA ของ `package_ref` ที่ trusted +- `source=npm`: `openclaw@beta`, `openclaw@latest` หรือ version รีลีส OpenClaw ที่แน่นอน +- `source=ref`: pack branch, tag หรือ full commit SHA ของ `package_ref` ที่เชื่อถือได้ ด้วย harness `workflow_ref` ที่เลือก - `source=url`: ดาวน์โหลด HTTPS `.tgz` พร้อม `package_sha256` ที่จำเป็น -- `source=artifact`: reuse `.tgz` ที่อัปโหลดโดย GitHub Actions run อื่น +- `source=artifact`: ใช้ `.tgz` ที่อัปโหลดโดย GitHub Actions run อื่นซ้ำ -`OpenClaw Release Checks` รัน Package Acceptance ด้วย `source=artifact`, -prepared release package artifact, `suite_profile=custom`, +`OpenClaw Release Checks` รัน Package Acceptance ด้วย `source=artifact`, package +artifact ของรีลีสที่เตรียมไว้, `suite_profile=custom`, `docker_lanes=doctor-switch update-channel-switch upgrade-survivor published-upgrade-survivor plugins-offline plugin-update`, `published_upgrade_survivor_baselines=all-since-2026.4.23`, `published_upgrade_survivor_scenarios=reported-issues` และ -`telegram_mode=mock-openai` Package Acceptance ทำให้ migration, update, การ cleanup -stale plugin dependency, offline plugin fixtures, plugin update และ Telegram -package QA ใช้ tarball ที่ resolve แล้วชุดเดียวกัน upgrade matrix ครอบคลุมทุก stable npm-published baseline ตั้งแต่ `2026.4.23` ถึง `latest`; ใช้ -Package Acceptance ด้วย `source=npm` สำหรับ candidate ที่ ship ไปแล้ว หรือ -`source=ref`/`source=artifact` สำหรับ tarball npm local ที่มี SHA รองรับก่อน -publish นี่คือสิ่งทดแทนแบบ GitHub-native -สำหรับ package/update coverage ส่วนใหญ่ที่ก่อนหน้านี้ต้องใช้ -Parallels Cross-OS release checks ยังสำคัญสำหรับ onboarding, installer และ -platform behavior เฉพาะ OS แต่การตรวจสอบผลิตภัณฑ์ package/update ควร -เลือกใช้ Package Acceptance +`telegram_mode=mock-openai` Package Acceptance เก็บ migration, update, การล้าง +dependency ของ Plugin เก่า, fixture ของ Plugin แบบ offline, การอัปเดต Plugin และ +Telegram package QA ไว้กับ tarball ที่ resolve แล้วเดียวกัน upgrade matrix ครอบคลุม +baseline stable ที่เผยแพร่บน npm ทุกตัวตั้งแต่ `2026.4.23` ถึง `latest`; ใช้ +Package Acceptance ด้วย `source=npm` สำหรับ candidate ที่ ship แล้ว หรือ +`source=ref`/`source=artifact` สำหรับ npm tarball ในเครื่องที่มี SHA รองรับก่อน publish +มันคือสิ่งทดแทนแบบ GitHub-native สำหรับความครอบคลุม package/update ส่วนใหญ่ที่ก่อนหน้า +ต้องใช้ Parallels การตรวจสอบรีลีสข้าม OS ยังสำคัญสำหรับ onboarding, installer และ +พฤติกรรมเฉพาะ platform แต่การตรวจสอบผลิตภัณฑ์ด้าน package/update ควรเลือกใช้ +Package Acceptance -checklist มาตรฐานสำหรับการตรวจสอบ update และ Plugin คือ -[การทดสอบ updates และ plugins](/th/help/testing-updates-plugins) ใช้เมื่อ -ตัดสินใจว่า local, Docker, Package Acceptance หรือ release-check lane ใดพิสูจน์ -การติดตั้ง/update Plugin, doctor cleanup หรือการเปลี่ยน migration ของ published-package ได้ -การ exhaustive published update migration จากทุกแพ็กเกจ stable `2026.4.23+` เป็น -workflow `Update Migration` แบบ manual แยกต่างหาก ไม่ได้เป็นส่วนหนึ่งของ Full Release CI +checklist canonical สำหรับการตรวจสอบ update และ Plugin คือ +[การทดสอบ updates และ plugins](/th/help/testing-updates-plugins) ใช้เมื่อจะตัดสินว่า +lane แบบ local, Docker, Package Acceptance หรือ release-check ใดพิสูจน์การ +ติดตั้ง/อัปเดต Plugin, การล้างด้วย doctor หรือการเปลี่ยนแปลง migration ของแพ็กเกจที่ +เผยแพร่แล้ว การ migration อัปเดตที่เผยแพร่แบบละเอียดจากทุกแพ็กเกจ stable +`2026.4.23+` เป็น workflow manual `Update Migration` แยกต่างหาก ไม่ใช่ส่วนหนึ่งของ +Full Release CI -ความผ่อนปรน legacy package-acceptance ถูกจำกัดเวลาด้วยเจตนา แพ็กเกจจนถึง -`2026.4.25` อาจใช้ compatibility path สำหรับ metadata gaps ที่เผยแพร่ไปยัง -npm แล้ว: private QA inventory entries ที่หายไปจาก tarball, ไม่มี -`gateway install --wrapper`, ไม่มี patch files ใน git fixture ที่ได้จาก tarball, -ไม่มี `update.channel` ที่ persisted, ตำแหน่ง install-record ของ legacy plugin, -ไม่มี marketplace install-record persistence และ config metadata -migration ระหว่าง `plugins update` แพ็กเกจ `2026.4.26` ที่เผยแพร่แล้วอาจ warn -สำหรับไฟล์ local build metadata stamp ที่ ship ไปแล้ว แพ็กเกจที่ใหม่กว่า -ต้องเป็นไปตาม package contracts สมัยใหม่; gaps เดียวกันนั้นจะทำให้ release -validation ล้มเหลว +ความผ่อนปรน legacy package-acceptance ถูกจำกัดเวลาโดยตั้งใจ แพ็กเกจจนถึง +`2026.4.25` อาจใช้ compatibility path สำหรับช่องว่าง metadata ที่เผยแพร่ไปยัง npm +แล้ว: รายการ inventory QA ส่วนตัวที่หายไปจาก tarball, `gateway install --wrapper` +ที่หายไป, ไฟล์ patch ที่หายไปใน git fixture ที่ได้จาก tarball, `update.channel` ที่ +persist หายไป, ตำแหน่ง legacy plugin install-record, persistence ของ marketplace +install-record ที่หายไป และการ migration config metadata ระหว่าง `plugins update` +แพ็กเกจ `2026.4.26` ที่เผยแพร่แล้วอาจ warn สำหรับไฟล์ stamp metadata ของ local build +ที่ ship ไปแล้ว แพ็กเกจหลังจากนั้นต้องเป็นไปตาม package contracts สมัยใหม่ +ช่องว่างเดียวกันเหล่านั้นจะทำให้ release validation ล้มเหลว -ใช้โปรไฟล์ Package Acceptance ที่กว้างขึ้นเมื่อคำถามของ release เกี่ยวกับ -แพ็กเกจที่ติดตั้งได้จริง: +ใช้โปรไฟล์ Package Acceptance ที่กว้างขึ้นเมื่อคำถามของรีลีสเกี่ยวกับแพ็กเกจที่ +ติดตั้งได้จริง: ```bash gh workflow run package-acceptance.yml \ @@ -410,32 +510,32 @@ gh workflow run package-acceptance.yml \ โปรไฟล์แพ็กเกจทั่วไป: -- `smoke`: เลนการติดตั้งแพ็กเกจ/ช่องทาง/เอเจนต์แบบเร็ว เครือข่าย Gateway และการโหลดการกำหนดค่าใหม่ -- `package`: สัญญาการติดตั้ง/อัปเดต/แพ็กเกจ Plugin โดยไม่มี ClawHub แบบไลฟ์; นี่เป็นค่าเริ่มต้นของการตรวจสอบรีลีส -- `product`: `package` รวมกับช่องทาง MCP, การล้าง cron/subagent, การค้นหาเว็บ OpenAI และ OpenWebUI -- `full`: ส่วนย่อยของเส้นทางรีลีส Docker พร้อม OpenWebUI +- `smoke`: เลนติดตั้งแพ็กเกจ/ช่องทาง/เอเจนต์แบบเร็ว, เครือข่าย Gateway, และโหลดการกำหนดค่าใหม่ +- `package`: สัญญาการติดตั้ง/อัปเดต/แพ็กเกจ Plugin โดยไม่มี ClawHub แบบสด; นี่คือค่าเริ่มต้นของการตรวจสอบรีลีส +- `product`: `package` รวมกับช่องทาง MCP, การล้าง cron/subagent, การค้นหาเว็บ OpenAI, และ OpenWebUI +- `full`: ส่วนของเส้นทางรีลีส Docker พร้อม OpenWebUI - `custom`: รายการ `docker_lanes` ที่แน่นอนสำหรับการรันซ้ำแบบเจาะจง สำหรับหลักฐาน Telegram ของแพ็กเกจตัวเลือก ให้เปิดใช้ `telegram_mode=mock-openai` หรือ `telegram_mode=live-frontier` บน Package Acceptance เวิร์กโฟลว์จะส่ง tarball -`package-under-test` ที่แก้ค่าแล้วเข้าไปยังเลน Telegram; เวิร์กโฟลว์ Telegram -แบบสแตนด์อโลนยังคงรับสเปก npm ที่เผยแพร่แล้วสำหรับการตรวจสอบหลังเผยแพร่ +`package-under-test` ที่แก้ค่าแล้วเข้าสู่เลน Telegram; เวิร์กโฟลว์ Telegram แบบสแตนด์อโลน +ยังรับสเปก npm ที่เผยแพร่แล้วสำหรับการตรวจสอบหลังเผยแพร่ -## ระบบอัตโนมัติสำหรับการเผยแพร่รีลีส +## การเผยแพร่รีลีสอัตโนมัติ -`OpenClaw Release Publish` คือจุดเข้าเผยแพร่แบบแก้ไขสถานะปกติ โดยจะจัดลำดับ -เวิร์กโฟลว์ trusted-publisher ตามที่รีลีสต้องการ: +`OpenClaw Release Publish` คือจุดเริ่มต้นการเผยแพร่แบบเปลี่ยนแปลงสถานะตามปกติ ซึ่ง +ประสานเวิร์กโฟลว์ trusted-publisher ตามลำดับที่รีลีสต้องใช้: 1. เช็กเอาต์แท็กรีลีสและแก้ค่า commit SHA ของแท็กนั้น -2. ตรวจสอบว่าแท็กสามารถเข้าถึงได้จาก `main` หรือ `release/*` +2. ตรวจสอบว่าแท็กเข้าถึงได้จาก `main` หรือ `release/*` 3. รัน `pnpm plugins:sync:check` -4. เรียกใช้ `Plugin NPM Release` ด้วย `publish_scope=all-publishable` และ +4. Dispatch `Plugin NPM Release` ด้วย `publish_scope=all-publishable` และ `ref=` -5. เรียกใช้ `Plugin ClawHub Release` ด้วยสโคปและ SHA เดียวกัน -6. เรียกใช้ `OpenClaw NPM Release` ด้วยแท็กรีลีส, npm dist-tag และ +5. Dispatch `Plugin ClawHub Release` ด้วย scope และ SHA เดียวกัน +6. Dispatch `OpenClaw NPM Release` ด้วยแท็กรีลีส, npm dist-tag, และ `preflight_run_id` ที่บันทึกไว้ -ตัวอย่างการเผยแพร่ Beta: +ตัวอย่างการเผยแพร่เบต้า: ```bash gh workflow run openclaw-release-publish.yml \ @@ -445,7 +545,7 @@ gh workflow run openclaw-release-publish.yml \ -f npm_dist_tag=beta ``` -เผยแพร่ Stable ไปยัง beta dist-tag เริ่มต้น: +การเผยแพร่เสถียรไปยัง dist-tag เบต้าเริ่มต้น: ```bash gh workflow run openclaw-release-publish.yml \ @@ -455,7 +555,7 @@ gh workflow run openclaw-release-publish.yml \ -f npm_dist_tag=beta ``` -การเลื่อน Stable ไปยัง `latest` โดยตรงต้องระบุอย่างชัดเจน: +การโปรโมตรีลีสเสถียรตรงไปยัง `latest` ต้องระบุอย่างชัดเจน: ```bash gh workflow run openclaw-release-publish.yml \ @@ -466,88 +566,88 @@ gh workflow run openclaw-release-publish.yml \ ``` ใช้เวิร์กโฟลว์ระดับล่าง `Plugin NPM Release` และ `Plugin ClawHub Release` -เฉพาะสำหรับงานซ่อมแซมหรือเผยแพร่ซ้ำแบบเจาะจงเท่านั้น สำหรับการซ่อมแซม Plugin -ที่เลือก ให้ส่ง `plugin_publish_scope=selected` และ `plugins=@openclaw/name` ไปยัง -`OpenClaw Release Publish` หรือเรียกใช้เวิร์กโฟลว์ลูกโดยตรงเมื่อไม่ควรเผยแพร่ +เฉพาะสำหรับงานซ่อมแซมหรือเผยแพร่ซ้ำแบบเจาะจงเท่านั้น สำหรับการซ่อมแซม Plugin ที่เลือกไว้ ให้ส่ง +`plugin_publish_scope=selected` และ `plugins=@openclaw/name` ไปยัง +`OpenClaw Release Publish` หรือ dispatch เวิร์กโฟลว์ลูกโดยตรงเมื่อไม่ควรเผยแพร่ แพ็กเกจ OpenClaw -## อินพุตของเวิร์กโฟลว์ NPM +## อินพุตเวิร์กโฟลว์ NPM -`OpenClaw NPM Release` รับอินพุตที่ควบคุมโดยผู้ปฏิบัติงานเหล่านี้: +`OpenClaw NPM Release` รับอินพุตที่ผู้ปฏิบัติงานควบคุมได้ดังนี้: -- `tag`: แท็กรีลีสที่จำเป็น เช่น `v2026.4.2`, `v2026.4.2-1` หรือ - `v2026.4.2-beta.1`; เมื่อ `preflight_only=true` ค่านี้อาจเป็น workflow-branch - commit SHA แบบครบ 40 อักขระปัจจุบันสำหรับ preflight แบบตรวจสอบเท่านั้นได้ด้วย -- `preflight_only`: `true` สำหรับการตรวจสอบ/บิลด์/แพ็กเกจเท่านั้น, `false` สำหรับ - เส้นทางเผยแพร่จริง -- `preflight_run_id`: จำเป็นบนเส้นทางเผยแพร่จริงเพื่อให้เวิร์กโฟลว์ใช้ tarball - ที่เตรียมไว้จากการรัน preflight ที่สำเร็จซ้ำ -- `npm_dist_tag`: แท็กเป้าหมายของ npm สำหรับเส้นทางเผยแพร่; ค่าเริ่มต้นคือ `beta` +- `tag`: แท็กรีลีสที่จำเป็น เช่น `v2026.4.2`, `v2026.4.2-1`, หรือ + `v2026.4.2-beta.1`; เมื่อ `preflight_only=true` ค่านี้อาจเป็น workflow-branch commit SHA + แบบเต็ม 40 อักขระปัจจุบันสำหรับ preflight ที่ใช้ตรวจสอบเท่านั้นได้ด้วย +- `preflight_only`: `true` สำหรับการตรวจสอบ/บิลด์/แพ็กเกจเท่านั้น, `false` สำหรับเส้นทาง + เผยแพร่จริง +- `preflight_run_id`: จำเป็นบนเส้นทางเผยแพร่จริงเพื่อให้เวิร์กโฟลว์ใช้ tarball ที่เตรียมไว้ + จากการรัน preflight ที่สำเร็จซ้ำ +- `npm_dist_tag`: แท็กเป้าหมาย npm สำหรับเส้นทางเผยแพร่; ค่าเริ่มต้นคือ `beta` -`OpenClaw Release Publish` รับอินพุตที่ควบคุมโดยผู้ปฏิบัติงานเหล่านี้: +`OpenClaw Release Publish` รับอินพุตที่ผู้ปฏิบัติงานควบคุมได้ดังนี้: - `tag`: แท็กรีลีสที่จำเป็น; ต้องมีอยู่แล้ว -- `preflight_run_id`: รหัสการรัน preflight ของ `OpenClaw NPM Release` ที่สำเร็จ; +- `preflight_run_id`: id การรัน preflight ของ `OpenClaw NPM Release` ที่สำเร็จ; จำเป็นเมื่อ `publish_openclaw_npm=true` -- `npm_dist_tag`: แท็กเป้าหมายของ npm สำหรับแพ็กเกจ OpenClaw +- `npm_dist_tag`: แท็กเป้าหมาย npm สำหรับแพ็กเกจ OpenClaw - `plugin_publish_scope`: ค่าเริ่มต้นคือ `all-publishable`; ใช้ `selected` เฉพาะ สำหรับงานซ่อมแซมแบบเจาะจง - `plugins`: ชื่อแพ็กเกจ `@openclaw/*` คั่นด้วยจุลภาคเมื่อ `plugin_publish_scope=selected` - `publish_openclaw_npm`: ค่าเริ่มต้นคือ `true`; ตั้งเป็น `false` เฉพาะเมื่อใช้ - เวิร์กโฟลว์เป็นตัวจัดลำดับการซ่อมแซมเฉพาะ Plugin เท่านั้น + เวิร์กโฟลว์เป็นตัวประสานงานการซ่อมแซมแบบเฉพาะ Plugin เท่านั้น -`OpenClaw Release Checks` รับอินพุตที่ควบคุมโดยผู้ปฏิบัติงานเหล่านี้: +`OpenClaw Release Checks` รับอินพุตที่ผู้ปฏิบัติงานควบคุมได้ดังนี้: -- `ref`: branch, tag หรือ full commit SHA ที่จะตรวจสอบ การตรวจสอบที่มี secret - ต้องให้ commit ที่แก้ค่าแล้วสามารถเข้าถึงได้จาก branch ของ OpenClaw หรือ - release tag +- `ref`: branch, tag, หรือ commit SHA แบบเต็มที่ต้องตรวจสอบ เช็กที่มี secret + ต้องให้ commit ที่แก้ค่าแล้วเข้าถึงได้จาก branch หรือแท็กรีลีสของ OpenClaw กฎ: -- แท็ก Stable และแท็กแก้ไขสามารถเผยแพร่ไปยัง `beta` หรือ `latest` ได้ -- แท็ก prerelease แบบ Beta สามารถเผยแพร่ได้เฉพาะไปยัง `beta` -- สำหรับ `OpenClaw NPM Release` อนุญาตให้ใช้อินพุต full commit SHA เฉพาะเมื่อ +- แท็กเสถียรและแท็กแก้ไขอาจเผยแพร่ไปยัง `beta` หรือ `latest` ก็ได้ +- แท็ก prerelease เบต้าอาจเผยแพร่ได้เฉพาะไปยัง `beta` +- สำหรับ `OpenClaw NPM Release` อนุญาตให้อินพุต commit SHA แบบเต็มได้เฉพาะเมื่อ `preflight_only=true` - `OpenClaw Release Checks` และ `Full Release Validation` เป็นแบบตรวจสอบเท่านั้นเสมอ - เส้นทางเผยแพร่จริงต้องใช้ `npm_dist_tag` เดียวกับที่ใช้ระหว่าง preflight; - เวิร์กโฟลว์จะตรวจสอบ metadata นั้นก่อนที่การเผยแพร่จะดำเนินต่อ + เวิร์กโฟลว์จะตรวจสอบว่าเมทาดาทาดังกล่าวยังคงถูกต้องก่อนเผยแพร่ต่อไป -## ลำดับการรีลีส npm แบบ Stable +## ลำดับการรีลีส npm แบบเสถียร -เมื่อตัดรีลีส npm แบบ Stable: +เมื่อตัดรีลีส npm แบบเสถียร: 1. รัน `OpenClaw NPM Release` ด้วย `preflight_only=true` - - ก่อนที่จะมีแท็ก คุณสามารถใช้ full workflow-branch commit SHA ปัจจุบัน - สำหรับ dry run ของเวิร์กโฟลว์ preflight แบบตรวจสอบเท่านั้น -2. เลือก `npm_dist_tag=beta` สำหรับโฟลว์ beta-first ปกติ หรือ `latest` เฉพาะเมื่อ - คุณตั้งใจต้องการเผยแพร่ Stable โดยตรง -3. รัน `Full Release Validation` บน release branch, release tag หรือ full - commit SHA เมื่อคุณต้องการ CI ปกติรวมกับ live prompt cache, Docker, QA Lab, - Matrix และความครอบคลุมของ Telegram จากเวิร์กโฟลว์แบบแมนนวลเดียว -4. หากคุณตั้งใจต้องการเฉพาะกราฟทดสอบปกติแบบกำหนดได้แน่นอน ให้รันเวิร์กโฟลว์ - `CI` แบบแมนนวลบน release ref แทน + - ก่อนมีแท็ก คุณอาจใช้ workflow-branch commit SHA แบบเต็มปัจจุบัน + สำหรับ dry run แบบตรวจสอบเท่านั้นของเวิร์กโฟลว์ preflight +2. เลือก `npm_dist_tag=beta` สำหรับโฟลว์ปกติแบบเบต้าก่อน หรือ `latest` เฉพาะ + เมื่อคุณตั้งใจต้องการเผยแพร่เสถียรโดยตรง +3. รัน `Full Release Validation` บน branch รีลีส, แท็กรีลีส, หรือ + commit SHA แบบเต็ม เมื่อต้องการ CI ปกติรวมกับ live prompt cache, Docker, QA Lab, + Matrix, และความครอบคลุมของ Telegram จากเวิร์กโฟลว์แบบแมนนวลเดียว +4. หากคุณตั้งใจต้องการเฉพาะกราฟทดสอบปกติแบบกำหนดแน่นอน ให้รันเวิร์กโฟลว์ + `CI` แบบแมนนวลบน ref รีลีสแทน 5. บันทึก `preflight_run_id` ที่สำเร็จ -6. รัน `OpenClaw Release Publish` ด้วย `tag` เดียวกัน, `npm_dist_tag` เดียวกัน - และ `preflight_run_id` ที่บันทึกไว้; เวิร์กโฟลว์จะเผยแพร่ Plugin ที่ถูกทำให้เป็นภายนอกไปยัง npm - และ ClawHub ก่อนเลื่อนแพ็กเกจ OpenClaw npm -7. หากรีลีสลงบน `beta` ให้ใช้เวิร์กโฟลว์ส่วนตัว +6. รัน `OpenClaw Release Publish` ด้วย `tag` เดียวกัน, `npm_dist_tag` เดียวกัน, + และ `preflight_run_id` ที่บันทึกไว้; เวิร์กโฟลว์จะเผยแพร่ Plugin ที่แยกออกภายนอกไปยัง npm + และ ClawHub ก่อนโปรโมตแพ็กเกจ npm ของ OpenClaw +7. หากรีลีสลงที่ `beta` ให้ใช้เวิร์กโฟลว์ส่วนตัว `openclaw/releases-private/.github/workflows/openclaw-npm-dist-tags.yml` - เพื่อเลื่อนเวอร์ชัน Stable นั้นจาก `beta` ไปยัง `latest` -8. หากรีลีสเผยแพร่โดยตรงไปยัง `latest` อย่างตั้งใจและ `beta` ควรตามบิลด์ Stable - เดียวกันทันที ให้ใช้เวิร์กโฟลว์ส่วนตัวเดียวกันนั้นเพื่อชี้ dist-tag ทั้งสองไปยังเวอร์ชัน Stable - หรือปล่อยให้การซิงก์ซ่อมแซมตัวเองตามกำหนดการย้าย `beta` ในภายหลัง + เพื่อโปรโมตเวอร์ชันเสถียรนั้นจาก `beta` ไปยัง `latest` +8. หากรีลีสตั้งใจเผยแพร่ตรงไปยัง `latest` และ `beta` + ควรตามบิลด์เสถียรเดียวกันทันที ให้ใช้เวิร์กโฟลว์ส่วนตัวเดียวกัน + เพื่อชี้ dist-tag ทั้งสองไปยังเวอร์ชันเสถียร หรือปล่อยให้การซิงก์แก้ไขตัวเองตามกำหนดการ + ย้าย `beta` ภายหลัง -การแก้ไข dist-tag อยู่ใน repo ส่วนตัวเพื่อความปลอดภัย เพราะยังต้องใช้ -`NPM_TOKEN` ในขณะที่ repo สาธารณะใช้การเผยแพร่แบบ OIDC เท่านั้น +การเปลี่ยนแปลง dist-tag อยู่ใน repo ส่วนตัวด้วยเหตุผลด้านความปลอดภัย เพราะยัง +ต้องใช้ `NPM_TOKEN` ขณะที่ repo สาธารณะคงการเผยแพร่แบบ OIDC-only ไว้ -สิ่งนี้ทำให้ทั้งเส้นทางเผยแพร่โดยตรงและเส้นทางเลื่อนแบบ beta-first -มีเอกสารกำกับและผู้ปฏิบัติงานมองเห็นได้ +สิ่งนี้ทำให้ทั้งเส้นทางเผยแพร่โดยตรงและเส้นทางโปรโมตแบบเบต้าก่อน +มีเอกสารครบถ้วนและผู้ปฏิบัติงานมองเห็นได้ -หาก maintainer จำเป็นต้อง fallback ไปใช้การยืนยันตัวตน npm ในเครื่อง ให้รันคำสั่ง -1Password CLI (`op`) ใด ๆ เฉพาะภายในเซสชัน tmux เฉพาะเท่านั้น อย่าเรียก `op` -โดยตรงจาก shell เอเจนต์หลัก; การเก็บไว้ภายใน tmux ทำให้ prompt, -alert และการจัดการ OTP สังเกตได้ และป้องกัน alert ของโฮสต์ที่เกิดซ้ำ +หาก maintainer ต้อง fallback ไปใช้การยืนยันตัวตน npm แบบ local ให้รันคำสั่ง 1Password +CLI (`op`) ใด ๆ เฉพาะในเซสชัน tmux เฉพาะเท่านั้น อย่าเรียก `op` +โดยตรงจากเชลล์เอเจนต์หลัก; การเก็บไว้ใน tmux ทำให้ prompt, +การแจ้งเตือน, และการจัดการ OTP สังเกตเห็นได้และป้องกันการแจ้งเตือน host ซ้ำ ## เอกสารอ้างอิงสาธารณะ diff --git a/docs/th/security/network-proxy.md b/docs/th/security/network-proxy.md index 9ed209a2b..d6a999e1a 100644 --- a/docs/th/security/network-proxy.md +++ b/docs/th/security/network-proxy.md @@ -1,40 +1,40 @@ --- read_when: - คุณต้องการการป้องกันเชิงลึกจากการโจมตีแบบ SSRF และการผูก DNS ใหม่ - - การกำหนดค่าพร็อกซีส่งต่อภายนอกสำหรับทราฟฟิกระหว่างการทำงานของ OpenClaw -summary: วิธีส่งต่อทราฟฟิก HTTP และ WebSocket ขณะรันไทม์ของ OpenClaw ผ่านพร็อกซีกรองที่ผู้ปฏิบัติงานจัดการ + - การกำหนดค่าพร็อกซีแบบส่งต่อภายนอกสำหรับทราฟฟิกขณะรันไทม์ของ OpenClaw +summary: วิธีกำหนดเส้นทางทราฟฟิก HTTP และ WebSocket ของรันไทม์ OpenClaw ผ่านพร็อกซีกรองที่จัดการโดยผู้ปฏิบัติการ title: พร็อกซีเครือข่าย x-i18n: - generated_at: "2026-05-04T02:26:06Z" + generated_at: "2026-05-04T07:07:03Z" model: gpt-5.5 provider: openai - source_hash: cd5594324e8c6b7da51d903e98fda0feacb8970e0b15d980f7a249d6641461c9 + source_hash: fc7140c5ced0e7454a6f85d1ea8f3256bbd28cc0cb42eeafe8e5e6439b90e3f0 source_path: security/network-proxy.md workflow: 16 --- # พร็อกซีเครือข่าย -OpenClaw สามารถกำหนดเส้นทางทราฟฟิก HTTP และ WebSocket ของรันไทม์ผ่านพร็อกซีแบบส่งต่อที่ผู้ปฏิบัติการจัดการได้ นี่เป็นการป้องกันเชิงลึกแบบไม่บังคับสำหรับการปรับใช้ที่ต้องการควบคุมทราฟฟิกขาออกจากศูนย์กลาง เพิ่มการป้องกัน SSRF ให้แข็งแรงขึ้น และตรวจสอบเครือข่ายได้ดียิ่งขึ้น +OpenClaw สามารถกำหนดเส้นทางทราฟฟิก HTTP และ WebSocket ขณะรันไทม์ผ่านพร็อกซีส่งต่อที่ผู้ปฏิบัติงานจัดการได้ นี่เป็นการป้องกันเชิงลึกแบบเลือกใช้ สำหรับการปรับใช้ที่ต้องการควบคุมทราฟฟิกขาออกจากศูนย์กลาง เพิ่มการป้องกัน SSRF ให้แข็งแรงขึ้น และตรวจสอบเครือข่ายได้ดียิ่งขึ้น -OpenClaw ไม่ได้จัดส่ง ดาวน์โหลด เริ่มต้น กำหนดค่า หรือรับรองพร็อกซี คุณเป็นผู้รันเทคโนโลยีพร็อกซีที่เหมาะกับสภาพแวดล้อมของคุณ และ OpenClaw จะกำหนดเส้นทางไคลเอนต์ HTTP และ WebSocket แบบปกติภายในโปรเซสผ่านพร็อกซีนั้น +OpenClaw ไม่ได้จัดส่ง ดาวน์โหลด เริ่มต้น กำหนดค่า หรือรับรองพร็อกซี คุณเป็นผู้รันเทคโนโลยีพร็อกซีที่เหมาะกับสภาพแวดล้อมของคุณ และ OpenClaw จะกำหนดเส้นทางไคลเอนต์ HTTP และ WebSocket ภายในโปรเซสตามปกติผ่านพร็อกซีนั้น ## ทำไมต้องใช้พร็อกซี? -พร็อกซีให้จุดควบคุมเครือข่ายจุดเดียวแก่ผู้ปฏิบัติการสำหรับทราฟฟิก HTTP และ WebSocket ขาออก ซึ่งมีประโยชน์ได้แม้นอกเหนือจากการเสริมความแข็งแรงด้าน SSRF: +พร็อกซีให้จุดควบคุมเครือข่ายจุดเดียวแก่ผู้ปฏิบัติงานสำหรับทราฟฟิก HTTP และ WebSocket ขาออก ซึ่งมีประโยชน์ได้แม้อยู่นอกเหนือจากการเสริมความแข็งแรงเพื่อป้องกัน SSRF: -- นโยบายจากศูนย์กลาง: ดูแลนโยบายขาออกเพียงชุดเดียว แทนการพึ่งพาให้ทุกจุดเรียก HTTP ของแอปพลิเคชันกำหนดกฎเครือข่ายให้ถูกต้อง -- การตรวจสอบ ณ เวลาที่เชื่อมต่อ: ประเมินปลายทางหลังจากการแก้ชื่อ DNS และทันทีก่อนที่พร็อกซีจะเปิดการเชื่อมต่อต้นทาง +- นโยบายส่วนกลาง: ดูแลนโยบายขาออกเพียงชุดเดียว แทนที่จะพึ่งให้ทุกจุดเรียก HTTP ของแอปพลิเคชันกำหนดกฎเครือข่ายให้ถูกต้องเอง +- การตรวจสอบ ณ เวลาเชื่อมต่อ: ประเมินปลายทางหลังการแก้ชื่อ DNS และทันทีก่อนที่พร็อกซีจะเปิดการเชื่อมต่อต้นทาง - การป้องกัน DNS rebinding: ลดช่องว่างระหว่างการตรวจสอบ DNS ระดับแอปพลิเคชันกับการเชื่อมต่อขาออกจริง -- ครอบคลุม JavaScript ได้กว้างขึ้น: กำหนดเส้นทาง `fetch`, `node:http`, `node:https`, WebSocket, axios, got, node-fetch และไคลเอนต์ที่คล้ายกันผ่านเส้นทางเดียวกัน -- ตรวจสอบย้อนหลังได้: บันทึกปลายทางที่อนุญาตและถูกปฏิเสธที่ขอบเขตขาออก -- การควบคุมเชิงปฏิบัติการ: บังคับใช้กฎปลายทาง การแบ่งส่วนเครือข่าย ขีดจำกัดอัตรา หรือรายการอนุญาตขาออกโดยไม่ต้องสร้าง OpenClaw ใหม่ +- ครอบคลุม JavaScript กว้างขึ้น: กำหนดเส้นทางไคลเอนต์ทั่วไปอย่าง `fetch`, `node:http`, `node:https`, WebSocket, axios, got, node-fetch และไคลเอนต์ลักษณะใกล้เคียงผ่านเส้นทางเดียวกัน +- การตรวจสอบย้อนหลัง: บันทึกปลายทางที่อนุญาตและปฏิเสธไว้ที่ขอบเขตทราฟฟิกขาออก +- การควบคุมเชิงปฏิบัติการ: บังคับใช้กฎปลายทาง การแบ่งส่วนเครือข่าย การจำกัดอัตรา หรือ allowlist ขาออกได้โดยไม่ต้องสร้าง OpenClaw ใหม่ -การกำหนดเส้นทางผ่านพร็อกซีเป็นแนวป้องกันระดับโปรเซสสำหรับทราฟฟิก HTTP และ WebSocket ขาออกแบบปกติ ช่วยให้ผู้ปฏิบัติการมีเส้นทางแบบล้มเหลวแล้วปิดกั้นสำหรับการกำหนดเส้นทางไคลเอนต์ HTTP ของ JavaScript ที่รองรับผ่านพร็อกซีกรองของตนเอง แต่ไม่ใช่แซนด์บ็อกซ์เครือข่ายระดับ OS และไม่ได้ทำให้ OpenClaw รับรองนโยบายปลายทางของพร็อกซี +การกำหนดเส้นทางพร็อกซีเป็นกรอบป้องกันระดับโปรเซสสำหรับ HTTP และ WebSocket ขาออกตามปกติ ช่วยให้ผู้ปฏิบัติงานมีเส้นทางแบบ fail-closed สำหรับกำหนดเส้นทางไคลเอนต์ HTTP ของ JavaScript ที่รองรับผ่านพร็อกซีกรองข้อมูลของตนเอง แต่ไม่ใช่ sandbox เครือข่ายระดับ OS และไม่ได้ทำให้ OpenClaw รับรองนโยบายปลายทางของพร็อกซี ## OpenClaw กำหนดเส้นทางทราฟฟิกอย่างไร -เมื่อกำหนดค่า `proxy.enabled=true` และตั้งค่า URL ของพร็อกซีแล้ว โปรเซสรันไทม์ที่ได้รับการป้องกัน เช่น `openclaw gateway run`, `openclaw node run` และ `openclaw agent --local` จะกำหนดเส้นทางทราฟฟิก HTTP และ WebSocket ขาออกแบบปกติผ่านพร็อกซีที่กำหนดค่าไว้: +เมื่อ `proxy.enabled=true` และมีการกำหนดค่า URL พร็อกซี โปรเซสรันไทม์ที่ได้รับการปกป้อง เช่น `openclaw gateway run`, `openclaw node run` และ `openclaw agent --local` จะกำหนดเส้นทาง HTTP และ WebSocket ขาออกตามปกติผ่านพร็อกซีที่กำหนดค่าไว้: ```text OpenClaw process @@ -43,27 +43,27 @@ OpenClaw process WebSocket clients -> operator-managed filtering proxy -> public internet ``` -สัญญาสาธารณะคือพฤติกรรมการกำหนดเส้นทาง ไม่ใช่ฮุกภายในของ Node ที่ใช้ติดตั้งใช้งาน OpenClaw Gateway control-plane WebSocket clients ใช้เส้นทางตรงแบบแคบสำหรับทราฟฟิก local loopback Gateway RPC เมื่อ URL ของ Gateway ใช้ `localhost` หรือ IP ลูปแบ็กแบบลิเทอรัล เช่น `127.0.0.1` หรือ `[::1]` เส้นทาง control-plane นั้นต้องสามารถเข้าถึง Gateway แบบลูปแบ็กได้ แม้พร็อกซีของผู้ปฏิบัติการจะบล็อกปลายทางลูปแบ็กก็ตาม คำขอ HTTP และ WebSocket ของรันไทม์แบบปกติยังคงใช้พร็อกซีที่กำหนดค่าไว้ +สัญญาสาธารณะคือพฤติกรรมการกำหนดเส้นทาง ไม่ใช่ hook ภายในของ Node ที่ใช้ในการนำไปใช้งาน ไคลเอนต์ WebSocket ใน control plane ของ OpenClaw Gateway ใช้เส้นทางตรงแบบแคบสำหรับทราฟฟิก RPC ของ Gateway ผ่าน local loopback เมื่อ URL ของ Gateway ใช้ `localhost` หรือ IP loopback แบบ literal เช่น `127.0.0.1` หรือ `[::1]` เส้นทาง control plane นั้นต้องสามารถเข้าถึง Gateway บน loopback ได้แม้พร็อกซีของผู้ปฏิบัติงานจะบล็อกปลายทาง loopback ก็ตาม คำขอ HTTP และ WebSocket ของรันไทม์ตามปกติยังคงใช้พร็อกซีที่กำหนดค่าไว้ -ภายใน OpenClaw ใช้ฮุกกำหนดเส้นทางระดับโปรเซสสองรายการสำหรับฟีเจอร์นี้: +ภายใน OpenClaw ใช้ hook การกำหนดเส้นทางระดับโปรเซสสองแบบสำหรับฟีเจอร์นี้: -- การกำหนดเส้นทางด้วย Undici dispatcher ครอบคลุม `fetch`, ไคลเอนต์ที่มี undici เป็นแบ็กเอนด์ และทรานสปอร์ตที่จัดเตรียม undici dispatcher ของตนเอง -- การกำหนดเส้นทางด้วย `global-agent` ครอบคลุมผู้เรียก Node core `node:http` และ `node:https` รวมถึงไลบรารีจำนวนมากที่ต่อยอดบน `http.request`, `https.request`, `http.get` และ `https.get` โหมดพร็อกซีที่จัดการจะบังคับใช้ global agent นั้น เพื่อไม่ให้ Node HTTP agents ที่ระบุอย่างชัดเจนเลี่ยงพร็อกซีของผู้ปฏิบัติการโดยไม่ตั้งใจ +- การกำหนดเส้นทางด้วย dispatcher ของ Undici ครอบคลุม `fetch`, ไคลเอนต์ที่มี undici รองรับ และ transport ที่มี dispatcher ของ undici เป็นของตนเอง +- การกำหนดเส้นทางด้วย `global-agent` ครอบคลุมผู้เรียก Node core `node:http` และ `node:https` รวมถึงไลบรารีจำนวนมากที่ต่อยอดบน `http.request`, `https.request`, `http.get` และ `https.get` โหมดพร็อกซีที่จัดการจะบังคับใช้ global agent นั้น เพื่อไม่ให้ agent ของ Node HTTP ที่ระบุไว้โดยตรงข้ามพร็อกซีของผู้ปฏิบัติงานโดยไม่ตั้งใจ -Plugin บางตัวเป็นเจ้าของทรานสปอร์ตแบบกำหนดเองที่ต้องต่อสายพร็อกซีอย่างชัดเจน แม้จะมีการกำหนดเส้นทางระดับโปรเซสอยู่แล้ว ตัวอย่างเช่น ทรานสปอร์ต Bot API ของ Telegram ใช้ HTTP/1 undici dispatcher ของตนเอง จึงเคารพ env พร็อกซีของโปรเซส รวมถึง fallback `OPENCLAW_PROXY_URL` ที่จัดการในเส้นทางทรานสปอร์ตเฉพาะเจ้าของนั้น +Plugin บางตัวมี transport แบบกำหนดเองที่ต้องเดินสายพร็อกซีอย่างชัดเจน แม้จะมีการกำหนดเส้นทางระดับโปรเซสอยู่แล้วก็ตาม ตัวอย่างเช่น transport ของ Bot API ใน Telegram ใช้ HTTP/1 undici dispatcher ของตัวเอง จึงเคารพ env พร็อกซีของโปรเซส รวมถึง fallback `OPENCLAW_PROXY_URL` ที่จัดการในเส้นทาง transport เฉพาะเจ้าของนั้น -URL ของพร็อกซีเองต้องใช้ `http://` ปลายทาง HTTPS ยังคงรองรับผ่านพร็อกซีด้วย HTTP `CONNECT`; ความหมายมีเพียงว่า OpenClaw คาดหวัง listener ของพร็อกซีแบบส่งต่อ HTTP ธรรมดา เช่น `http://127.0.0.1:3128` +URL ของพร็อกซีเองต้องใช้ `http://` ปลายทาง HTTPS ยังคงรองรับผ่านพร็อกซีด้วย HTTP `CONNECT`; นี่หมายความเพียงว่า OpenClaw คาดหวัง listener ของพร็อกซีส่งต่อ HTTP แบบธรรมดา เช่น `http://127.0.0.1:3128` -ขณะที่พร็อกซีทำงานอยู่ OpenClaw จะล้าง `no_proxy`, `NO_PROXY` และ `GLOBAL_AGENT_NO_PROXY` รายการ bypass เหล่านั้นอิงตามปลายทาง ดังนั้นหากปล่อย `localhost` หรือ `127.0.0.1` ไว้ในนั้น จะทำให้เป้าหมาย SSRF ที่มีความเสี่ยงสูงข้ามพร็อกซีกรองได้ +ขณะที่พร็อกซีทำงานอยู่ OpenClaw จะล้าง `no_proxy`, `NO_PROXY` และ `GLOBAL_AGENT_NO_PROXY` รายการข้ามเหล่านี้อิงตามปลายทาง ดังนั้นหากปล่อย `localhost` หรือ `127.0.0.1` ไว้ในนั้น จะทำให้เป้าหมาย SSRF ความเสี่ยงสูงข้ามพร็อกซีกรองข้อมูลได้ เมื่อปิดการทำงาน OpenClaw จะกู้คืนสภาพแวดล้อมพร็อกซีก่อนหน้าและรีเซ็ตสถานะการกำหนดเส้นทางของโปรเซสที่แคชไว้ -## คำศัพท์ที่เกี่ยวข้องกับพร็อกซี +## คำศัพท์เกี่ยวกับพร็อกซีที่เกี่ยวข้อง -- `proxy.enabled` / `proxy.proxyUrl`: การกำหนดเส้นทางขาออกผ่านพร็อกซีแบบส่งต่อสำหรับทราฟฟิกขาออกของรันไทม์ OpenClaw หน้านี้จัดทำเอกสารฟีเจอร์ดังกล่าว -- `gateway.auth.mode: "trusted-proxy"`: การยืนยันตัวตนขาเข้าแบบ reverse-proxy ที่รับรู้ตัวตนสำหรับการเข้าถึง Gateway ดู [การยืนยันตัวตนพร็อกซีที่เชื่อถือได้](/th/gateway/trusted-proxy-auth) -- `openclaw proxy`: พร็อกซีดีบักภายในเครื่องและตัวตรวจสอบการจับข้อมูลสำหรับการพัฒนาและการสนับสนุน ดู [openclaw proxy](/th/cli/proxy) -- การตั้งค่าพร็อกซีเฉพาะ channel หรือ provider: การแทนที่เฉพาะเจ้าของสำหรับทรานสปอร์ตหนึ่งรายการ ควรใช้พร็อกซีเครือข่ายที่จัดการเมื่อเป้าหมายคือการควบคุมทราฟฟิกขาออกจากศูนย์กลางทั่วทั้งรันไทม์ +- `proxy.enabled` / `proxy.proxyUrl`: การกำหนดเส้นทางพร็อกซีส่งต่อขาออกสำหรับทราฟฟิกขาออกของรันไทม์ OpenClaw หน้านี้อธิบายฟีเจอร์นั้น +- `gateway.auth.mode: "trusted-proxy"`: การยืนยันตัวตนขาเข้าผ่าน reverse proxy ที่รับรู้ตัวตนสำหรับการเข้าถึง Gateway ดู [การยืนยันตัวตนผ่านพร็อกซีที่เชื่อถือได้](/th/gateway/trusted-proxy-auth) +- `openclaw proxy`: พร็อกซีดีบักในเครื่องและตัวตรวจสอบการจับข้อมูลสำหรับการพัฒนาและการสนับสนุน ดู [openclaw proxy](/th/cli/proxy) +- การตั้งค่าพร็อกซีเฉพาะช่องทางหรือ provider: override เฉพาะเจ้าของสำหรับ transport รายใดรายหนึ่ง ควรใช้พร็อกซีเครือข่ายที่จัดการเมื่อเป้าหมายคือการควบคุมทราฟฟิกขาออกจากศูนย์กลางทั่วทั้งรันไทม์ ## การกำหนดค่า @@ -73,7 +73,7 @@ proxy: proxyUrl: http://127.0.0.1:3128 ``` -คุณยังสามารถระบุ URL ผ่านสภาพแวดล้อมได้ โดยคง `proxy.enabled=true` ไว้ในการกำหนดค่า: +คุณยังสามารถระบุ URL ผ่านสภาพแวดล้อมได้ โดยยังคงตั้ง `proxy.enabled=true` ไว้ใน config: ```bash OPENCLAW_PROXY_URL=http://127.0.0.1:3128 openclaw gateway run @@ -81,9 +81,9 @@ OPENCLAW_PROXY_URL=http://127.0.0.1:3128 openclaw gateway run `proxy.proxyUrl` มีลำดับความสำคัญเหนือ `OPENCLAW_PROXY_URL` -หาก `enabled=true` แต่ไม่มี URL พร็อกซีที่ถูกต้องได้รับการกำหนดค่า คำสั่งที่ได้รับการป้องกันจะเริ่มต้นไม่สำเร็จ แทนที่จะ fallback ไปใช้การเข้าถึงเครือข่ายโดยตรง +หาก `enabled=true` แต่ไม่มี URL พร็อกซีที่ถูกต้องกำหนดไว้ คำสั่งที่ได้รับการปกป้องจะเริ่มต้นล้มเหลวแทนที่จะ fallback ไปใช้การเข้าถึงเครือข่ายโดยตรง -สำหรับบริการ Gateway ที่จัดการซึ่งเริ่มด้วย `openclaw gateway start` ควรจัดเก็บ URL ไว้ในการกำหนดค่า: +สำหรับบริการ gateway ที่จัดการซึ่งเริ่มด้วย `openclaw gateway start` ควรเก็บ URL ไว้ใน config: ```bash openclaw config set proxy.enabled true @@ -92,9 +92,9 @@ openclaw gateway install --force openclaw gateway start ``` -fallback ผ่านสภาพแวดล้อมเหมาะที่สุดสำหรับการรันแบบ foreground หากคุณใช้กับบริการที่ติดตั้งแล้ว ให้ใส่ `OPENCLAW_PROXY_URL` ในสภาพแวดล้อมถาวรของบริการ เช่น `$OPENCLAW_STATE_DIR/.env` หรือ `~/.openclaw/.env` จากนั้นติดตั้งบริการใหม่เพื่อให้ launchd, systemd หรือ Scheduled Tasks เริ่ม Gateway พร้อมค่านั้น +fallback ผ่านสภาพแวดล้อมเหมาะที่สุดสำหรับการรันแบบ foreground หากคุณใช้กับบริการที่ติดตั้งแล้ว ให้ใส่ `OPENCLAW_PROXY_URL` ในสภาพแวดล้อมถาวรของบริการ เช่น `$OPENCLAW_STATE_DIR/.env` หรือ `~/.openclaw/.env` แล้วติดตั้งบริการใหม่ เพื่อให้ launchd, systemd หรือ Scheduled Tasks เริ่ม gateway พร้อมค่านั้น -สำหรับคำสั่ง `openclaw --container ...` OpenClaw จะส่งต่อ `OPENCLAW_PROXY_URL` ไปยัง CLI ลูกที่มุ่งเป้าไปยังคอนเทนเนอร์เมื่อมีการตั้งค่า URL ต้องเข้าถึงได้จากภายในคอนเทนเนอร์; `127.0.0.1` หมายถึงตัวคอนเทนเนอร์เอง ไม่ใช่โฮสต์ OpenClaw จะปฏิเสธ URL พร็อกซีลูปแบ็กสำหรับคำสั่งที่มุ่งเป้าไปยังคอนเทนเนอร์ เว้นแต่คุณจะแทนที่การตรวจสอบความปลอดภัยนั้นอย่างชัดเจน +สำหรับคำสั่ง `openclaw --container ...` OpenClaw จะส่งต่อ `OPENCLAW_PROXY_URL` เข้าไปยัง CLI ลูกที่มีเป้าหมายเป็นคอนเทนเนอร์เมื่อมีการตั้งค่า URL ต้องเข้าถึงได้จากภายในคอนเทนเนอร์; `127.0.0.1` หมายถึงตัวคอนเทนเนอร์เอง ไม่ใช่โฮสต์ OpenClaw จะปฏิเสธ URL พร็อกซีแบบ loopback สำหรับคำสั่งที่มีเป้าหมายเป็นคอนเทนเนอร์ เว้นแต่คุณจะ override การตรวจสอบความปลอดภัยนั้นอย่างชัดเจน ## ข้อกำหนดของพร็อกซี @@ -102,41 +102,41 @@ fallback ผ่านสภาพแวดล้อมเหมาะที่ กำหนดค่าพร็อกซีให้: -- ผูกกับลูปแบ็กหรืออินเทอร์เฟซส่วนตัวที่เชื่อถือได้เท่านั้น -- จำกัดการเข้าถึงเพื่อให้เฉพาะโปรเซส OpenClaw, โฮสต์, คอนเทนเนอร์ หรือบัญชีบริการเท่านั้นที่ใช้งานได้ -- แก้ชื่อปลายทางเองและบล็อก IP ปลายทางหลังจากการแก้ชื่อ DNS -- ใช้นโยบาย ณ เวลาที่เชื่อมต่อสำหรับทั้งคำขอ HTTP ธรรมดาและทันเนล HTTPS `CONNECT` -- ปฏิเสธ bypass ที่อิงตามปลายทางสำหรับช่วงลูปแบ็ก ส่วนตัว link-local เมทาดาทา multicast สงวนไว้ หรือเอกสารประกอบ -- หลีกเลี่ยงรายการอนุญาตตามชื่อโฮสต์ เว้นแต่คุณจะเชื่อถือเส้นทางการแก้ชื่อ DNS อย่างเต็มที่ -- บันทึกปลายทาง การตัดสินใจ สถานะ และเหตุผล โดยไม่บันทึกเนื้อหาคำขอ เฮดเดอร์ authorization คุกกี้ หรือความลับอื่น -- เก็บนโยบายพร็อกซีไว้ภายใต้การควบคุมเวอร์ชัน และตรวจสอบการเปลี่ยนแปลงเหมือนการกำหนดค่าที่อ่อนไหวด้านความปลอดภัย +- bind เฉพาะกับ loopback หรืออินเทอร์เฟซส่วนตัวที่เชื่อถือได้ +- จำกัดการเข้าถึงเพื่อให้มีเพียงโปรเซส OpenClaw, โฮสต์, คอนเทนเนอร์ หรือบัญชีบริการเท่านั้นที่ใช้งานได้ +- แก้ชื่อปลายทางเองและบล็อก IP ปลายทางหลังการแก้ชื่อ DNS +- ใช้นโยบาย ณ เวลาเชื่อมต่อสำหรับทั้งคำขอ HTTP แบบธรรมดาและ tunnel HTTPS `CONNECT` +- ปฏิเสธการข้ามตามปลายทางสำหรับช่วง loopback, private, link-local, metadata, multicast, reserved หรือ documentation +- หลีกเลี่ยง allowlist ชื่อโฮสต์ เว้นแต่คุณจะเชื่อถือเส้นทางการแก้ชื่อ DNS อย่างเต็มที่ +- บันทึกปลายทาง การตัดสินใจ สถานะ และเหตุผล โดยไม่บันทึกเนื้อหาคำขอ header การอนุญาต cookie หรือความลับอื่นๆ +- เก็บนโยบายพร็อกซีไว้ในระบบควบคุมเวอร์ชันและรีวิวการเปลี่ยนแปลงเหมือนการกำหนดค่าที่อ่อนไหวด้านความปลอดภัย ## ปลายทางที่แนะนำให้บล็อก -ใช้รายการ denylist นี้เป็นจุดเริ่มต้นสำหรับพร็อกซีแบบส่งต่อ ไฟร์วอลล์ หรือนโยบายขาออกใดๆ +ใช้ denylist นี้เป็นจุดเริ่มต้นสำหรับพร็อกซีส่งต่อ ไฟร์วอลล์ หรือนโยบายทราฟฟิกขาออกใดๆ -ตรรกะ classifier ระดับแอปพลิเคชันของ OpenClaw อยู่ใน `src/infra/net/ssrf.ts` และ `src/shared/net/ip.ts` parity hooks ที่เกี่ยวข้องคือ `BLOCKED_HOSTNAMES`, `BLOCKED_IPV4_SPECIAL_USE_RANGES`, `BLOCKED_IPV6_SPECIAL_USE_RANGES`, `RFC2544_BENCHMARK_PREFIX` และการจัดการ sentinel ของ IPv4 แบบฝังสำหรับ NAT64, 6to4, Teredo, ISATAP และรูปแบบ IPv4-mapped ไฟล์เหล่านี้เป็นข้อมูลอ้างอิงที่มีประโยชน์เมื่อดูแลนโยบายพร็อกซีภายนอก แต่ OpenClaw ไม่ได้ส่งออกหรือบังคับใช้กฎเหล่านั้นในพร็อกซีของคุณโดยอัตโนมัติ +ตรรกะตัวจัดประเภทระดับแอปพลิเคชันของ OpenClaw อยู่ใน `src/infra/net/ssrf.ts` และ `src/shared/net/ip.ts` hook ที่เกี่ยวข้องสำหรับ parity คือ `BLOCKED_HOSTNAMES`, `BLOCKED_IPV4_SPECIAL_USE_RANGES`, `BLOCKED_IPV6_SPECIAL_USE_RANGES`, `RFC2544_BENCHMARK_PREFIX` และการจัดการ sentinel IPv4 แบบฝังสำหรับ NAT64, 6to4, Teredo, ISATAP และรูปแบบ IPv4-mapped ไฟล์เหล่านั้นเป็นข้อมูลอ้างอิงที่มีประโยชน์เมื่อดูแลนโยบายพร็อกซีภายนอก แต่ OpenClaw ไม่ได้ส่งออกหรือบังคับใช้กฎเหล่านั้นในพร็อกซีของคุณโดยอัตโนมัติ -| ช่วงหรือโฮสต์ | เหตุผลที่ต้องบล็อก | +| ช่วงหรือโฮสต์ | เหตุผลที่ควรบล็อก | | ------------------------------------------------------------------------------------ | ---------------------------------------------------- | -| `127.0.0.0/8`, `localhost`, `localhost.localdomain` | ลูปแบ็ก IPv4 | -| `::1/128` | ลูปแบ็ก IPv6 | +| `127.0.0.0/8`, `localhost`, `localhost.localdomain` | IPv4 loopback | +| `::1/128` | IPv6 loopback | | `0.0.0.0/8`, `::/128` | ที่อยู่แบบไม่ระบุและที่อยู่ this-network | | `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16` | เครือข่ายส่วนตัว RFC1918 | -| `169.254.0.0/16`, `fe80::/10` | ที่อยู่ link-local และเส้นทางเมทาดาทาคลาวด์ทั่วไป | -| `169.254.169.254`, `metadata.google.internal` | บริการเมทาดาทาคลาวด์ | -| `100.64.0.0/10` | พื้นที่ที่อยู่ร่วมของ NAT ระดับผู้ให้บริการ | +| `169.254.0.0/16`, `fe80::/10` | ที่อยู่ link-local และเส้นทาง metadata ของคลาวด์ที่พบบ่อย | +| `169.254.169.254`, `metadata.google.internal` | บริการ metadata ของคลาวด์ | +| `100.64.0.0/10` | พื้นที่ที่อยู่ร่วมกันของ carrier-grade NAT | | `198.18.0.0/15`, `2001:2::/48` | ช่วงสำหรับ benchmarking | -| `192.0.0.0/24`, `192.0.2.0/24`, `198.51.100.0/24`, `203.0.113.0/24`, `2001:db8::/32` | ช่วง special-use และเอกสารประกอบ | +| `192.0.0.0/24`, `192.0.2.0/24`, `198.51.100.0/24`, `203.0.113.0/24`, `2001:db8::/32` | ช่วง special-use และ documentation | | `224.0.0.0/4`, `ff00::/8` | Multicast | | `240.0.0.0/4` | IPv4 ที่สงวนไว้ | -| `fc00::/7`, `fec0::/10` | ช่วง IPv6 ภายใน/ส่วนตัว | -| `100::/64`, `2001:20::/28` | ช่วง IPv6 discard และ ORCHIDv2 | -| `64:ff9b::/96`, `64:ff9b:1::/48` | คำนำหน้า NAT64 ที่มี IPv4 ฝังอยู่ | +| `fc00::/7`, `fec0::/10` | ช่วง local/private ของ IPv6 | +| `100::/64`, `2001:20::/28` | ช่วง discard และ ORCHIDv2 ของ IPv6 | +| `64:ff9b::/96`, `64:ff9b:1::/48` | prefix NAT64 ที่มี IPv4 ฝังอยู่ | | `2002::/16`, `2001::/32` | 6to4 และ Teredo ที่มี IPv4 ฝังอยู่ | -| `::/96`, `::ffff:0:0/96` | IPv6 แบบเข้ากันได้กับ IPv4 และ IPv6 แบบ IPv4-mapped | +| `::/96`, `::ffff:0:0/96` | IPv6 แบบ IPv4-compatible และ IPv4-mapped | -หากผู้ให้บริการคลาวด์หรือแพลตฟอร์มเครือข่ายของคุณจัดทำเอกสารโฮสต์เมทาดาทาหรือช่วงที่สงวนไว้เพิ่มเติม ให้เพิ่มรายการเหล่านั้นด้วย +หากผู้ให้บริการคลาวด์หรือแพลตฟอร์มเครือข่ายของคุณมีเอกสารระบุโฮสต์ metadata หรือช่วงที่สงวนไว้เพิ่มเติม ให้เพิ่มรายการเหล่านั้นด้วย ## การตรวจสอบความถูกต้อง @@ -146,9 +146,9 @@ fallback ผ่านสภาพแวดล้อมเหมาะที่ openclaw proxy validate --proxy-url http://127.0.0.1:3128 ``` -โดยค่าเริ่มต้น เมื่อไม่ได้ระบุปลายทางแบบกำหนดเอง คำสั่งจะตรวจสอบว่า `https://example.com/` สำเร็จ และเริ่ม canary ลูปแบ็กชั่วคราวที่พร็อกซีต้องเข้าถึงไม่ได้ การตรวจสอบการปฏิเสธเริ่มต้นจะผ่านเมื่อพร็อกซีส่งคืนการตอบกลับปฏิเสธที่ไม่ใช่ 2xx หรือบล็อก canary ด้วยความล้มเหลวของทรานสปอร์ต; จะล้มเหลวหากการตอบกลับที่สำเร็จเข้าถึง canary หากไม่มีพร็อกซีที่เปิดใช้และกำหนดค่าไว้ การตรวจสอบความถูกต้องจะรายงานปัญหาการกำหนดค่า; ใช้ `--proxy-url` สำหรับ preflight แบบครั้งเดียวก่อนเปลี่ยนการกำหนดค่า ใช้ `--allowed-url` และ `--denied-url` เพื่อทดสอบความคาดหวังเฉพาะการปรับใช้ ปลายทางที่ถูกปฏิเสธแบบกำหนดเองจะล้มเหลวแบบปิดกั้น: การตอบกลับ HTTP ใดๆ หมายถึงปลายทางเข้าถึงได้ผ่านพร็อกซี และข้อผิดพลาดของทรานสปอร์ตใดๆ จะถูกรายงานว่าไม่สามารถสรุปได้ เพราะ OpenClaw ไม่สามารถพิสูจน์ได้ว่าพร็อกซีบล็อก origin ที่เข้าถึงได้ เมื่อการตรวจสอบความถูกต้องล้มเหลว คำสั่งจะออกด้วยรหัส 1 +โดยค่าเริ่มต้น เมื่อไม่ได้ระบุปลายทางแบบกำหนดเอง คำสั่งจะตรวจสอบว่า `https://example.com/` สำเร็จ และเริ่ม canary แบบ loopback ชั่วคราวที่พร็อกซีต้องไม่เข้าถึง การตรวจสอบที่คาดว่าถูกปฏิเสธโดยค่าเริ่มต้นจะผ่านเมื่อพร็อกซีส่งคืนการปฏิเสธแบบ non-2xx หรือบล็อก canary ด้วยความล้มเหลวของ transport; จะล้มเหลวหากการตอบกลับที่สำเร็จไปถึง canary หากไม่มีพร็อกซีที่เปิดใช้และกำหนดค่าไว้ การตรวจสอบจะรายงานปัญหา config; ใช้ `--proxy-url` สำหรับ preflight แบบครั้งเดียวก่อนเปลี่ยน config ใช้ `--allowed-url` และ `--denied-url` เพื่อทดสอบความคาดหวังเฉพาะการปรับใช้ ปลายทางที่ถูกปฏิเสธแบบกำหนดเองเป็นแบบ fail-closed: การตอบกลับ HTTP ใดๆ หมายความว่าปลายทางนั้นเข้าถึงได้ผ่านพร็อกซี และข้อผิดพลาด transport ใดๆ จะถูกรายงานว่าไม่สามารถสรุปได้ เพราะ OpenClaw ไม่สามารถพิสูจน์ได้ว่าพร็อกซีบล็อก origin ที่เข้าถึงได้ เมื่อการตรวจสอบล้มเหลว คำสั่งจะออกด้วยรหัส 1 -ใช้ `--json` สำหรับระบบอัตโนมัติ เอาต์พุต JSON ประกอบด้วยผลลัพธ์โดยรวม แหล่งที่มาของการกำหนดค่าพร็อกซีที่มีผล ข้อผิดพลาดการกำหนดค่าใดๆ และการตรวจสอบปลายทางแต่ละรายการ ข้อมูลประจำตัวของ URL พร็อกซีจะถูกปกปิดในเอาต์พุตแบบข้อความและ JSON: +ใช้ `--json` สำหรับการทำ automation เอาต์พุต JSON มีผลลัพธ์รวม แหล่งที่มาของ config พร็อกซีที่มีผล ข้อผิดพลาด config ใดๆ และการตรวจสอบแต่ละปลายทาง credential ใน URL พร็อกซีจะถูกปิดบังทั้งในเอาต์พุตข้อความและ JSON: ```json { @@ -170,7 +170,7 @@ openclaw proxy validate --proxy-url http://127.0.0.1:3128 } ``` -คุณยังสามารถตรวจสอบด้วยตนเองด้วย `curl`: +คุณสามารถตรวจสอบด้วยตนเองด้วย `curl` ได้เช่นกัน: ```bash curl -x http://127.0.0.1:3128 https://example.com/ @@ -178,7 +178,7 @@ curl -x http://127.0.0.1:3128 http://127.0.0.1/ curl -x http://127.0.0.1:3128 http://169.254.169.254/ ``` -คำขอสาธารณะควรสำเร็จ คำขอ loopback และ metadata ควรถูกบล็อกโดยพร็อกซี สำหรับ `openclaw proxy validate` ตัวตรวจสอบ loopback canary ในตัวสามารถแยกการปฏิเสธจากพร็อกซีกับ origin ที่เข้าถึงได้ การตรวจสอบ `--denied-url` แบบกำหนดเองไม่มี canary ดังกล่าว ดังนั้นให้ถือว่าทั้งการตอบกลับ HTTP และความล้มเหลวด้านการขนส่งที่กำกวมเป็นความล้มเหลวในการตรวจสอบ เว้นแต่พร็อกซีของคุณจะเปิดเผยสัญญาณการปฏิเสธเฉพาะการปรับใช้ที่คุณสามารถตรวจสอบแยกต่างหากได้ +คำขอสาธารณะควรสำเร็จ ส่วนคำขอ loopback และ metadata ควรถูกพร็อกซีบล็อก สำหรับ `openclaw proxy validate` นั้น canary loopback ในตัวสามารถแยกแยะการปฏิเสธจากพร็อกซีออกจากต้นทางที่เข้าถึงได้ การตรวจสอบ `--denied-url` แบบกำหนดเองไม่มี canary ดังกล่าว ดังนั้นให้ถือว่าทั้งการตอบกลับ HTTP และความล้มเหลวด้านการส่งข้อมูลที่กำกวมเป็นความล้มเหลวของการตรวจสอบ เว้นแต่ว่าพร็อกซีของคุณเปิดเผยสัญญาณการปฏิเสธเฉพาะการปรับใช้ที่คุณสามารถตรวจสอบแยกต่างหากได้ จากนั้นเปิดใช้การกำหนดเส้นทางพร็อกซีของ OpenClaw: @@ -198,10 +198,11 @@ proxy: ## ขีดจำกัด -- พร็อกซีช่วยเพิ่มการครอบคลุมสำหรับไคลเอนต์ HTTP และ WebSocket ของ JavaScript ที่อยู่ภายในโปรเซส แต่ไม่ใช่ sandbox เครือข่ายระดับระบบปฏิบัติการ -- ซ็อกเก็ต `net`, `tls` และ `http2` แบบดิบ, native addons และโปรเซสลูก อาจเลี่ยงการกำหนดเส้นทางพร็อกซีระดับ Node ได้ เว้นแต่จะสืบทอดและเคารพตัวแปรสภาพแวดล้อมของพร็อกซี -- IRC เป็นช่องทาง TCP/TLS แบบดิบที่อยู่นอกการกำหนดเส้นทาง forward proxy ที่ผู้ปฏิบัติงานจัดการ ในการปรับใช้ที่กำหนดให้ egress ทั้งหมดผ่าน forward proxy นั้น ให้ตั้งค่า `channels.irc.enabled=false` เว้นแต่ egress ของ IRC โดยตรงจะได้รับอนุมัติอย่างชัดเจน -- WebUI ภายในเครื่องของผู้ใช้และเซิร์ฟเวอร์โมเดลภายในเครื่องควรถูกเพิ่มใน allowlist ในนโยบายพร็อกซีของผู้ปฏิบัติงานเมื่อจำเป็น OpenClaw ไม่ได้เปิดเผยการข้ามเครือข่ายภายในเครื่องแบบทั่วไปสำหรับสิ่งเหล่านี้ -- การข้ามพร็อกซีของ control-plane ของ Gateway ถูกจำกัดไว้ที่ `localhost` และ URL IP loopback แบบระบุโดยตรงโดยเจตนา ใช้ `ws://127.0.0.1:18789`, `ws://[::1]:18789` หรือ `ws://localhost:18789` สำหรับการเชื่อมต่อ control-plane ของ Gateway โดยตรงภายในเครื่อง ชื่อโฮสต์อื่นจะถูกกำหนดเส้นทางเหมือนทราฟฟิกที่อิงตามชื่อโฮสต์ทั่วไป +- พร็อกซีช่วยเพิ่มความครอบคลุมสำหรับไคลเอ็นต์ HTTP และ WebSocket ของ JavaScript ที่อยู่ภายในกระบวนการ แต่ไม่ใช่แซนด์บ็อกซ์เครือข่ายระดับ OS +- ซ็อกเก็ต `net`, `tls`, และ `http2` แบบดิบ, native addons, และกระบวนการลูก อาจเลี่ยงการกำหนดเส้นทางพร็อกซีระดับ Node ได้ เว้นแต่ว่าจะสืบทอดและเคารพตัวแปรสภาพแวดล้อมของพร็อกซี +- IRC เป็นช่องทาง TCP/TLS แบบดิบที่อยู่นอกการกำหนดเส้นทางผ่านพร็อกซีส่งต่อที่ผู้ปฏิบัติการจัดการ ในการปรับใช้ที่กำหนดให้อีเกรสทั้งหมดต้องผ่านพร็อกซีส่งต่อนั้น ให้ตั้งค่า `channels.irc.enabled=false` เว้นแต่ว่าอีเกรส IRC โดยตรงจะได้รับอนุมัติอย่างชัดเจน +- พร็อกซีดีบักภายในเครื่องเป็นเครื่องมือวินิจฉัย และการส่งต่ออัปสตรีมโดยตรงสำหรับคำขอพร็อกซีและ CONNECT tunnels จะถูกปิดใช้งานตามค่าเริ่มต้นขณะที่โหมดพร็อกซีที่จัดการอยู่ทำงานอยู่ ให้เปิดใช้การส่งต่อโดยตรงเฉพาะสำหรับการวินิจฉัยภายในเครื่องที่ได้รับอนุมัติเท่านั้น +- WebUI ภายในเครื่องของผู้ใช้และเซิร์ฟเวอร์โมเดลภายในเครื่องควรถูกเพิ่มลงในรายการอนุญาตในนโยบายพร็อกซีของผู้ปฏิบัติการเมื่อจำเป็น OpenClaw ไม่ได้เปิดเผยการเลี่ยงเครือข่ายภายในเครื่องแบบทั่วไปสำหรับสิ่งเหล่านี้ +- การเลี่ยงพร็อกซีของ control plane ของ Gateway ถูกจำกัดไว้ที่ `localhost` และ URL ที่เป็น IP loopback ตามตัวอักษรโดยตั้งใจ ใช้ `ws://127.0.0.1:18789`, `ws://[::1]:18789`, หรือ `ws://localhost:18789` สำหรับการเชื่อมต่อ control plane ของ Gateway ภายในเครื่องโดยตรง ชื่อโฮสต์อื่นจะถูกกำหนดเส้นทางเหมือนทราฟฟิกที่อิงตามชื่อโฮสต์ทั่วไป - OpenClaw ไม่ตรวจสอบ ทดสอบ หรือรับรองนโยบายพร็อกซีของคุณ -- ให้ถือว่าการเปลี่ยนแปลงนโยบายพร็อกซีเป็นการเปลี่ยนแปลงการดำเนินงานที่อ่อนไหวด้านความปลอดภัย +- ให้ถือว่าการเปลี่ยนแปลงนโยบายพร็อกซีเป็นการเปลี่ยนแปลงการปฏิบัติงานที่มีความอ่อนไหวด้านความปลอดภัย diff --git a/docs/th/tools/subagents.md b/docs/th/tools/subagents.md index 9e2f42658..7d08e753c 100644 --- a/docs/th/tools/subagents.md +++ b/docs/th/tools/subagents.md @@ -1,40 +1,46 @@ --- read_when: - - คุณต้องการทำงานเบื้องหลังหรือทำงานแบบขนานผ่านเอเจนต์ - - คุณกำลังเปลี่ยนแปลง sessions_spawn หรือนโยบายของเครื่องมือตัวแทนย่อย - - คุณกำลังนำเซสชันเอเจนต์ย่อยที่ผูกกับเธรดไปใช้ หรือกำลังแก้ไขปัญหาเซสชันดังกล่าว + - คุณต้องการงานเบื้องหลังหรืองานแบบขนานผ่านเอเจนต์ + - คุณกำลังเปลี่ยนแปลง sessions_spawn หรือนโยบายเครื่องมือของเอเจนต์ย่อย + - คุณกำลังพัฒนาหรือแก้ไขปัญหาเซสชันเอเจนต์ย่อยที่ผูกกับเธรด sidebarTitle: Sub-agents -summary: สร้างการรันเอเจนต์พื้นหลังแบบแยกอิสระ ซึ่งประกาศผลลัพธ์กลับไปยังแชตของผู้ร้องขอ +summary: เริ่มการรันเอเจนต์เบื้องหลังแบบแยกส่วน ซึ่งประกาศผลลัพธ์กลับไปยังแชตของผู้ร้องขอ title: เอเจนต์ย่อย x-i18n: - generated_at: "2026-05-04T02:27:42Z" + generated_at: "2026-05-04T07:07:15Z" model: gpt-5.5 provider: openai - source_hash: d0df39e06b952def3eb0b296f36c7dc8c0b0a115785d865236a970c5d453fc37 + source_hash: 65d60bf6813d667b7311aa28109d4bd6be012a16e638c64cfff130831db88cd8 source_path: tools/subagents.md workflow: 16 --- เอเจนต์ย่อยคือการรันเอเจนต์เบื้องหลังที่ถูกสร้างจากการรันเอเจนต์ที่มีอยู่ -เอเจนต์เหล่านี้รันในเซสชันของตัวเอง (`agent::subagent:`) และ -เมื่อเสร็จสิ้น จะ**ประกาศ**ผลลัพธ์กลับไปยังช่องแชตของผู้ร้องขอ +เอเจนต์ย่อยจะทำงานในเซสชันของตัวเอง (`agent::subagent:`) และ +เมื่อเสร็จแล้วจะ **ประกาศ** ผลลัพธ์กลับไปยังช่องแชทของผู้ร้องขอ การรันเอเจนต์ย่อยแต่ละครั้งจะถูกติดตามเป็น [งานเบื้องหลัง](/th/automation/tasks) เป้าหมายหลัก: -- ทำให้งาน "วิจัย / งานยาว / เครื่องมือที่ช้า" รันแบบขนานได้โดยไม่บล็อกการรันหลัก -- แยกเอเจนต์ย่อยออกจากกันตามค่าเริ่มต้น (การแยกเซสชัน + sandboxing แบบเลือกได้) -- ทำให้พื้นผิวเครื่องมือใช้งานผิดได้ยาก: เอเจนต์ย่อยจะ**ไม่ได้**รับเครื่องมือเซสชันตามค่าเริ่มต้น -- รองรับความลึกของการซ้อนที่กำหนดค่าได้สำหรับรูปแบบ orchestrator +- ทำงาน "ค้นคว้า / งานยาว / เครื่องมือช้า" แบบขนานโดยไม่บล็อกการรันหลัก +- แยกเอเจนต์ย่อยโดยค่าเริ่มต้น (แยกเซสชัน + sandboxing ที่เลือกได้) +- ทำให้พื้นผิวเครื่องมือถูกใช้งานผิดได้ยาก: เอเจนต์ย่อยจะไม่ได้รับเครื่องมือเซสชันโดยค่าเริ่มต้น +- รองรับความลึกการซ้อนที่กำหนดค่าได้สำหรับรูปแบบ orchestrator -**หมายเหตุด้านต้นทุน:** เอเจนต์ย่อยแต่ละตัวมีบริบทและการใช้โทเค็นของตัวเองตามค่าเริ่มต้น สำหรับงานหนักหรืองานซ้ำ ให้ตั้งโมเดลที่ถูกกว่าสำหรับเอเจนต์ย่อยและคงเอเจนต์หลักไว้บนโมเดลคุณภาพสูงกว่า กำหนดค่าผ่าน `agents.defaults.subagents.model` หรือการ override รายเอเจนต์ เมื่อลูกต้องการ transcript ปัจจุบันของผู้ร้องขอจริง ๆ เอเจนต์สามารถขอ `context: "fork"` สำหรับการ spawn ครั้งนั้นได้ เซสชัน subagent ที่ผูกกับเธรดมีค่าเริ่มต้นเป็น `context: "fork"` เพราะจะแตกกิ่งบทสนทนาปัจจุบันไปยังเธรดติดตามผล +**หมายเหตุเรื่องต้นทุน:** โดยค่าเริ่มต้น เอเจนต์ย่อยแต่ละตัวมีบริบทและการใช้โทเค็นของตัวเอง +สำหรับงานหนักหรืองานที่ทำซ้ำ ให้ตั้งโมเดลที่ถูกกว่าสำหรับเอเจนต์ย่อย +และให้เอเจนต์หลักใช้โมเดลคุณภาพสูงกว่า กำหนดค่าผ่าน +`agents.defaults.subagents.model` หรือการ override รายเอเจนต์ เมื่อเอเจนต์ลูก + ต้องการทรานสคริปต์ปัจจุบันของผู้ร้องขอจริง ๆ เอเจนต์สามารถขอ + `context: "fork"` สำหรับการ spawn ครั้งนั้นได้ เซสชันเอเจนต์ย่อยที่ผูกกับเธรดมีค่าเริ่มต้นเป็น + `context: "fork"` เพราะจะแตกแขนงบทสนทนาปัจจุบันไปยังเธรดติดตามผล -## คำสั่ง slash +## คำสั่ง Slash -ใช้ `/subagents` เพื่อตรวจสอบหรือควบคุมการรันเอเจนต์ย่อยสำหรับ**เซสชันปัจจุบัน**: +ใช้ `/subagents` เพื่อตรวจสอบหรือควบคุมการรันเอเจนต์ย่อยสำหรับ **เซสชันปัจจุบัน**: ```text /subagents list @@ -46,15 +52,17 @@ x-i18n: /subagents spawn [--model ] [--thinking ] ``` -ใช้ [`/steer `](/th/tools/steer) ระดับบนสุดเพื่อ steer การรันที่ใช้งานอยู่ของเซสชันผู้ร้องขอปัจจุบัน ใช้ `/subagents steer ` เมื่อเป้าหมายเป็นการรันลูก +ใช้ [`/steer `](/th/tools/steer) ระดับบนสุดเพื่อบังคับทิศทางการรันที่ใช้งานอยู่ของเซสชันผู้ร้องขอปัจจุบัน ใช้ `/subagents steer ` เมื่อเป้าหมายเป็นการรันลูก -`/subagents info` แสดงข้อมูลเมตาของการรัน (สถานะ, timestamp, id เซสชัน, -พาธ transcript, cleanup) ใช้ `sessions_history` สำหรับมุมมองการเรียกดูย้อนหลังที่มีขอบเขตและผ่านการกรองความปลอดภัยแล้ว; ตรวจสอบพาธ transcript บนดิสก์เมื่อคุณต้องการ transcript ฉบับเต็มแบบดิบ +`/subagents info` แสดงเมทาดาทาของการรัน (สถานะ, เวลา, id เซสชัน, +พาธทรานสคริปต์, การล้างข้อมูล) ใช้ `sessions_history` สำหรับมุมมองการเรียกคืนแบบจำกัดขอบเขต +และกรองความปลอดภัยแล้ว ตรวจสอบพาธทรานสคริปต์บนดิสก์เมื่อคุณ +ต้องการทรานสคริปต์เต็มดิบ ### การควบคุมการผูกเธรด -คำสั่งเหล่านี้ทำงานบนช่องที่รองรับการผูกเธรดแบบคงอยู่ -ดู [ช่องที่รองรับเธรด](#thread-supporting-channels) ด้านล่าง +คำสั่งเหล่านี้ทำงานบนช่องทางที่รองรับการผูกเธรดแบบถาวร +ดู [ช่องทางที่รองรับเธรด](#thread-supporting-channels) ด้านล่าง ```text /focus @@ -64,74 +72,79 @@ x-i18n: /session max-age ``` -### พฤติกรรมการ spawn +### พฤติกรรมการ Spawn -`/subagents spawn` เริ่มเอเจนต์ย่อยเบื้องหลังในฐานะคำสั่งของผู้ใช้ (ไม่ใช่ relay ภายใน) และส่งการอัปเดตการเสร็จสิ้นขั้นสุดท้ายหนึ่งครั้งกลับไปยังแชตของผู้ร้องขอเมื่อการรันเสร็จสิ้น +`/subagents spawn` เริ่มเอเจนต์ย่อยเบื้องหลังในฐานะคำสั่งของผู้ใช้ (ไม่ใช่ +relay ภายใน) และส่งอัปเดตการเสร็จสิ้นสุดท้ายหนึ่งครั้งกลับไปยัง +แชทของผู้ร้องขอเมื่อการรันเสร็จสิ้น - - คำสั่ง spawn ไม่บล็อก; จะคืน id การรันทันที - - เมื่อเสร็จสิ้น เอเจนต์ย่อยจะประกาศข้อความสรุป/ผลลัพธ์กลับไปยังช่องแชตของผู้ร้องขอ - - การเสร็จสิ้นเป็นแบบ push-based หลังจาก spawn แล้ว อย่า poll `/subagents list`, `sessions_list`, หรือ `sessions_history` เป็นลูปเพียงเพื่อรอให้เสร็จ; ตรวจสอบสถานะเฉพาะเมื่อจำเป็นสำหรับการดีบักหรือการแทรกแซง - - เมื่อเสร็จสิ้น OpenClaw จะพยายามปิดแท็บ/โปรเซสเบราว์เซอร์ที่ติดตามไว้ซึ่งเปิดโดยเซสชันเอเจนต์ย่อยนั้นก่อนที่โฟลว์ cleanup ของการประกาศจะดำเนินต่อ + - คำสั่ง spawn เป็นแบบไม่บล็อก และจะคืน id การรันทันที + - เมื่อเสร็จสิ้น เอเจนต์ย่อยจะประกาศข้อความสรุป/ผลลัพธ์กลับไปยังช่องแชทของผู้ร้องขอ + - การเสร็จสิ้นเป็นแบบ push-based เมื่อ spawn แล้ว อย่า poll `/subagents list`, `sessions_list`, หรือ `sessions_history` ในลูปเพียงเพื่อรอให้เสร็จ ให้ตรวจสอบสถานะเฉพาะเมื่อจำเป็นสำหรับการดีบักหรือการแทรกแซงเท่านั้น + - เมื่อเสร็จสิ้น OpenClaw จะพยายามปิดแท็บเบราว์เซอร์/โปรเซสที่ติดตามไว้ซึ่งเปิดโดยเซสชันเอเจนต์ย่อยนั้น ก่อนที่โฟลว์การล้างข้อมูลของการประกาศจะดำเนินต่อ - - OpenClaw ลองส่งมอบ `agent` โดยตรงก่อนด้วย idempotency key ที่เสถียร - - หากการส่งมอบโดยตรงล้มเหลว จะ fallback ไปใช้การ routing ผ่านคิว - - หากการ routing ผ่านคิวยังใช้ไม่ได้ การประกาศจะถูก retry ด้วย exponential backoff สั้น ๆ ก่อนยอมแพ้ขั้นสุดท้าย - - การส่งมอบเมื่อเสร็จสิ้นจะคง route ของผู้ร้องขอที่ resolve แล้ว: route การเสร็จสิ้นที่ผูกกับเธรดหรือผูกกับบทสนทนาจะชนะเมื่อมีให้ใช้; หากต้นทางการเสร็จสิ้นให้มาเพียง channel, OpenClaw จะเติม target/account ที่หายไปจาก route ที่ resolve แล้วของเซสชันผู้ร้องขอ (`lastChannel` / `lastTo` / `lastAccountId`) เพื่อให้การส่งมอบโดยตรงยังทำงานได้ + - OpenClaw จะลองส่งแบบ `agent` โดยตรงก่อนด้วยคีย์ idempotency ที่เสถียร + - หากรอบการเสร็จสิ้นของเอเจนต์ผู้ร้องขอล้มเหลว ไม่มีเอาต์พุตที่มองเห็นได้ หรือคืน prefix ที่ไม่สมบูรณ์อย่างชัดเจนของผลลัพธ์ลูกที่จับไว้ OpenClaw จะ fallback ไปส่งการเสร็จสิ้นโดยตรงจากผลลัพธ์ลูกที่จับไว้ + - หากใช้การส่งโดยตรงไม่ได้ จะ fallback ไปยังการกำหนดเส้นทางผ่านคิว + - หากการกำหนดเส้นทางผ่านคิวยังใช้ไม่ได้ การประกาศจะถูกลองซ้ำด้วย exponential backoff สั้น ๆ ก่อนยอมแพ้ขั้นสุดท้าย + - การส่งการเสร็จสิ้นจะรักษาเส้นทางผู้ร้องขอที่ resolve แล้ว: เส้นทางการเสร็จสิ้นที่ผูกกับเธรดหรือผูกกับบทสนทนาจะชนะเมื่อพร้อมใช้งาน หากต้นทางการเสร็จสิ้นให้มาเฉพาะช่องทาง OpenClaw จะเติมเป้าหมาย/บัญชีที่ขาดจากเส้นทางที่ resolve แล้วของเซสชันผู้ร้องขอ (`lastChannel` / `lastTo` / `lastAccountId`) เพื่อให้การส่งโดยตรงยังทำงานได้ - การ handoff การเสร็จสิ้นไปยังเซสชันผู้ร้องขอเป็นบริบทภายในที่สร้างโดย runtime (ไม่ใช่ข้อความที่ผู้ใช้เขียน) และประกอบด้วย: + การส่งมอบการเสร็จสิ้นให้เซสชันผู้ร้องขอเป็นบริบทภายในที่ runtime สร้างขึ้น + (ไม่ใช่ข้อความที่ผู้ใช้เขียน) และประกอบด้วย: - - `Result` — ข้อความตอบกลับ `assistant` ที่มองเห็นล่าสุด มิฉะนั้นเป็นข้อความ tool/toolResult ล่าสุดที่ sanitize แล้ว การรันที่ล้มเหลวแบบสิ้นสุดจะไม่นำข้อความตอบกลับที่จับไว้กลับมาใช้ซ้ำ + - `Result` — ข้อความตอบกลับ `assistant` ล่าสุดที่มองเห็นได้ มิฉะนั้นเป็นข้อความ tool/toolResult ล่าสุดที่ผ่านการทำให้ปลอดภัยแล้ว การรันที่ล้มเหลวแบบ terminal จะไม่นำข้อความตอบกลับที่จับไว้มาใช้ซ้ำ - `Status` — `completed successfully` / `failed` / `timed out` / `unknown` - - สถิติ runtime/token แบบย่อ - - คำสั่งการส่งมอบที่บอกเอเจนต์ผู้ร้องขอให้เขียนใหม่ด้วยเสียง assistant ปกติ (ไม่ส่งต่อ metadata ภายในแบบดิบ) + - สถิติ runtime/โทเค็นแบบกระชับ + - คำสั่งการส่งที่บอกเอเจนต์ผู้ร้องขอให้เขียนใหม่ด้วยเสียงผู้ช่วยปกติ (ไม่ส่งต่อเมทาดาทาภายในแบบดิบ) - `--model` และ `--thinking` override ค่าเริ่มต้นสำหรับการรันนั้นโดยเฉพาะ - - ใช้ `info`/`log` เพื่อตรวจสอบรายละเอียดและเอาต์พุตหลังเสร็จสิ้น - - `/subagents spawn` เป็นโหมด one-shot (`mode: "run"`) สำหรับเซสชันแบบคงอยู่ที่ผูกกับเธรด ให้ใช้ `sessions_spawn` พร้อม `thread: true` และ `mode: "session"` - - สำหรับเซสชัน harness ของ ACP (Claude Code, Gemini CLI, OpenCode, หรือ Codex ACP/acpx ที่ระบุชัดเจน) ให้ใช้ `sessions_spawn` พร้อม `runtime: "acp"` เมื่อเครื่องมือประกาศ runtime นั้น ดู [โมเดลการส่งมอบของ ACP](/th/tools/acp-agents#delivery-model) เมื่อดีบักการเสร็จสิ้นหรือลูป agent-to-agent เมื่อเปิดใช้งาน Plugin `codex` การควบคุมแชต/เธรดของ Codex ควรเลือกใช้ `/codex ...` แทน ACP เว้นแต่ผู้ใช้จะขอ ACP/acpx อย่างชัดเจน - - OpenClaw ซ่อน `runtime: "acp"` จนกว่า ACP จะเปิดใช้งาน ผู้ร้องขอไม่ได้อยู่ใน sandbox และมีการโหลด Plugin backend เช่น `acpx` แล้ว `runtime: "acp"` คาดหวัง id harness ACP ภายนอก หรือรายการ `agents.list[]` ที่มี `runtime.type="acp"`; ใช้ runtime เอเจนต์ย่อยค่าเริ่มต้นสำหรับเอเจนต์ config ของ OpenClaw ปกติจาก `agents_list` + - ใช้ `info`/`log` เพื่อตรวจสอบรายละเอียดและเอาต์พุตหลังจากเสร็จสิ้น + - `/subagents spawn` เป็นโหมด one-shot (`mode: "run"`) สำหรับเซสชันถาวรที่ผูกกับเธรด ให้ใช้ `sessions_spawn` พร้อม `thread: true` และ `mode: "session"` + - สำหรับเซสชัน ACP harness (Claude Code, Gemini CLI, OpenCode หรือ Codex ACP/acpx ที่ระบุชัดเจน) ให้ใช้ `sessions_spawn` พร้อม `runtime: "acp"` เมื่อเครื่องมือประกาศ runtime นั้น ดู [โมเดลการส่งของ ACP](/th/tools/acp-agents#delivery-model) เมื่อดีบักการเสร็จสิ้นหรือลูปเอเจนต์ต่อเอเจนต์ เมื่อเปิดใช้งาน Plugin `codex` การควบคุมแชท/เธรด Codex ควรเลือกใช้ `/codex ...` แทน ACP เว้นแต่ผู้ใช้จะขอ ACP/acpx อย่างชัดเจน + - OpenClaw ซ่อน `runtime: "acp"` จนกว่าจะเปิดใช้งาน ACP, ผู้ร้องขอไม่ได้อยู่ใน sandbox และมีการโหลด Plugin แบ็กเอนด์ เช่น `acpx` แล้ว `runtime: "acp"` คาดหวัง id ของ ACP harness ภายนอก หรือรายการ `agents.list[]` ที่มี `runtime.type="acp"`; ใช้ runtime เอเจนต์ย่อยเริ่มต้นสำหรับเอเจนต์ config ปกติของ OpenClaw จาก `agents_list` ## โหมดบริบท -เอเจนต์ย่อยแบบ native จะเริ่มแบบแยกเดี่ยว เว้นแต่ผู้เรียกจะขอ fork -transcript ปัจจุบันอย่างชัดเจน +เอเจนต์ย่อยแบบ native เริ่มแบบแยกเดี่ยว เว้นแต่ผู้เรียกจะขอ fork +ทรานสคริปต์ปัจจุบันอย่างชัดเจน | โหมด | ควรใช้เมื่อใด | พฤติกรรม | | ---------- | -------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- | -| `isolated` | การวิจัยใหม่, การ implementation อิสระ, งานเครื่องมือที่ช้า, หรือสิ่งใดก็ตามที่สามารถสรุปในข้อความงานได้ | สร้าง transcript ลูกที่สะอาด นี่คือค่าเริ่มต้นและช่วยลดการใช้โทเค็น | -| `fork` | งานที่ขึ้นกับบทสนทนาปัจจุบัน, ผลลัพธ์เครื่องมือก่อนหน้า, หรือคำสั่งที่ละเอียดอ่อนซึ่งมีอยู่แล้วใน transcript ของผู้ร้องขอ | แตกกิ่ง transcript ของผู้ร้องขอไปยังเซสชันลูกก่อนที่ลูกจะเริ่ม | +| `isolated` | การค้นคว้าใหม่, การนำไปใช้ที่เป็นอิสระ, งานเครื่องมือช้า หรือสิ่งใดก็ตามที่สรุปงานในข้อความงานได้ | สร้างทรานสคริปต์ลูกใหม่สะอาด นี่คือค่าเริ่มต้นและช่วยลดการใช้โทเค็น | +| `fork` | งานที่ขึ้นกับบทสนทนาปัจจุบัน, ผลลัพธ์เครื่องมือก่อนหน้า หรือคำสั่งที่มีรายละเอียดอ่อนซึ่งมีอยู่แล้วในทรานสคริปต์ของผู้ร้องขอ | แตกแขนงทรานสคริปต์ของผู้ร้องขอเข้าสู่เซสชันลูกก่อนที่ลูกจะเริ่ม | -ใช้ `fork` อย่างประหยัด มีไว้สำหรับการมอบหมายงานที่อ่อนไหวต่อบริบท ไม่ใช่ -สิ่งทดแทนการเขียน prompt งานที่ชัดเจน +ใช้ `fork` เท่าที่จำเป็น ใช้สำหรับการมอบหมายงานที่ไวต่อบริบท ไม่ใช่ +สิ่งทดแทนการเขียนพรอมป์งานที่ชัดเจน ## เครื่องมือ: `sessions_spawn` -เริ่มการรันเอเจนต์ย่อยด้วย `deliver: false` บน lane `subagent` ระดับ global -จากนั้นรันขั้นตอนประกาศและโพสต์คำตอบประกาศไปยังช่องแชตของผู้ร้องขอ +เริ่มการรันเอเจนต์ย่อยด้วย `deliver: false` บนเลน `subagent` ส่วนกลาง +จากนั้นรันขั้นตอนประกาศและโพสต์คำตอบประกาศไปยังช่องแชทของผู้ร้องขอ -ความพร้อมใช้งานขึ้นอยู่กับนโยบายเครื่องมือที่มีผลของผู้เรียก โปรไฟล์ `coding` และ -`full` เปิดเผย `sessions_spawn` ตามค่าเริ่มต้น โปรไฟล์ `messaging` -ไม่เปิดเผย; เพิ่ม `tools.alsoAllow: ["sessions_spawn", "sessions_yield", -"subagents"]` หรือใช้ `tools.profile: "coding"` สำหรับเอเจนต์ที่ควรมอบหมายงานได้ -นโยบาย allow/deny ของ channel/group, provider, sandbox และรายเอเจนต์ยังสามารถ -ลบเครื่องมือนี้หลังขั้นตอนโปรไฟล์ได้ ใช้ `/tools` จากเซสชันเดียวกันเพื่อยืนยันรายการเครื่องมือที่มีผล +ความพร้อมใช้งานขึ้นกับนโยบายเครื่องมือที่มีผลของผู้เรียก โปรไฟล์ `coding` และ +`full` เปิดเผย `sessions_spawn` โดยค่าเริ่มต้น โปรไฟล์ `messaging` +ไม่เปิดเผย ให้เพิ่ม `tools.alsoAllow: ["sessions_spawn", "sessions_yield", +"subagents"]` หรือใช้ `tools.profile: "coding"` สำหรับเอเจนต์ที่ควรมอบหมาย +งาน นโยบายช่องทาง/กลุ่ม, provider, sandbox และ allow/deny รายเอเจนต์ยังสามารถ +นำเครื่องมือออกหลังขั้นโปรไฟล์ได้ ใช้ `/tools` จากเซสชันเดียวกัน +เพื่อยืนยันรายการเครื่องมือที่มีผล **ค่าเริ่มต้น:** - **โมเดล:** สืบทอดจากผู้เรียก เว้นแต่คุณตั้ง `agents.defaults.subagents.model` (หรือ `agents.list[].subagents.model` รายเอเจนต์); `sessions_spawn.model` ที่ระบุชัดเจนยังคงชนะ - **Thinking:** สืบทอดจากผู้เรียก เว้นแต่คุณตั้ง `agents.defaults.subagents.thinking` (หรือ `agents.list[].subagents.thinking` รายเอเจนต์); `sessions_spawn.thinking` ที่ระบุชัดเจนยังคงชนะ -- **ระยะหมดเวลาการรัน:** หากละ `sessions_spawn.runTimeoutSeconds`, OpenClaw จะใช้ `agents.defaults.subagents.runTimeoutSeconds` เมื่อมีการตั้งค่าไว้; มิฉะนั้นจะ fallback เป็น `0` (ไม่มี timeout) +- **ไทม์เอาต์การรัน:** หากละ `sessions_spawn.runTimeoutSeconds` ไว้ OpenClaw จะใช้ `agents.defaults.subagents.runTimeoutSeconds` เมื่อมีการตั้งค่า มิฉะนั้นจะ fallback เป็น `0` (ไม่มีไทม์เอาต์) ### พารามิเตอร์เครื่องมือ @@ -139,144 +152,145 @@ transcript ปัจจุบันอย่างชัดเจน คำอธิบายงานสำหรับเอเจนต์ย่อย - ป้ายกำกับที่มนุษย์อ่านได้แบบเลือกได้ + ป้ายกำกับที่มนุษย์อ่านได้ซึ่งเป็นทางเลือก - Spawn ภายใต้ id เอเจนต์อื่นเมื่อ `subagents.allowAgents` อนุญาต + Spawn ภายใต้ id เอเจนต์อื่นเมื่อได้รับอนุญาตโดย `subagents.allowAgents` - `acp` ใช้เฉพาะสำหรับ harness ACP ภายนอก (`claude`, `droid`, `gemini`, `opencode`, หรือ Codex ACP/acpx ที่ร้องขออย่างชัดเจน) และสำหรับรายการ `agents.list[]` ที่ `runtime.type` เป็น `acp` + `acp` ใช้เฉพาะสำหรับ ACP harness ภายนอก (`claude`, `droid`, `gemini`, `opencode` หรือ Codex ACP/acpx ที่ขออย่างชัดเจน) และสำหรับรายการ `agents.list[]` ที่ `runtime.type` เป็น `acp` - เฉพาะ ACP Resume เซสชัน harness ACP ที่มีอยู่เมื่อ `runtime: "acp"`; ถูกละเว้นสำหรับการ spawn เอเจนต์ย่อยแบบ native + เฉพาะ ACP เท่านั้น ดำเนินเซสชัน ACP harness ที่มีอยู่ต่อเมื่อ `runtime: "acp"`; ถูกละเว้นสำหรับการ spawn เอเจนต์ย่อยแบบ native - เฉพาะ ACP สตรีมเอาต์พุตการรัน ACP ไปยังเซสชันแม่เมื่อ `runtime: "acp"`; ละเว้นสำหรับการ spawn เอเจนต์ย่อยแบบ native + เฉพาะ ACP เท่านั้น สตรีมเอาต์พุตการรัน ACP ไปยังเซสชันแม่เมื่อ `runtime: "acp"`; ละไว้สำหรับการ spawn เอเจนต์ย่อยแบบ native - Override โมเดลเอเจนต์ย่อย ค่าที่ไม่ถูกต้องจะถูกข้ามและเอเจนต์ย่อยจะรันบนโมเดลค่าเริ่มต้นพร้อมคำเตือนในผลลัพธ์เครื่องมือ + Override โมเดลเอเจนต์ย่อย ค่าที่ไม่ถูกต้องจะถูกข้ามและเอเจนต์ย่อยจะรันบนโมเดลเริ่มต้นพร้อมคำเตือนในผลลัพธ์เครื่องมือ Override ระดับ thinking สำหรับการรันเอเจนต์ย่อย - ค่าเริ่มต้นเป็น `agents.defaults.subagents.runTimeoutSeconds` เมื่อมีการตั้งค่า มิฉะนั้นเป็น `0` เมื่อมีการตั้งค่า การรันเอเจนต์ย่อยจะถูก abort หลัง N วินาที + ค่าเริ่มต้นเป็น `agents.defaults.subagents.runTimeoutSeconds` เมื่อมีการตั้งค่า มิฉะนั้นเป็น `0` เมื่อตั้งค่าแล้ว การรันเอเจนต์ย่อยจะถูกยกเลิกหลังจาก N วินาที - เมื่อเป็น `true` จะขอการผูกเธรดของช่องสำหรับเซสชันเอเจนต์ย่อยนี้ + เมื่อเป็น `true` จะขอการผูกเธรดของช่องทางสำหรับเซสชันเอเจนต์ย่อยนี้ - หากละ `thread: true` และ `mode` ค่าเริ่มต้นจะกลายเป็น `session` `mode: "session"` ต้องใช้ `thread: true` + หาก `thread: true` และละ `mode` ไว้ ค่าเริ่มต้นจะกลายเป็น `session` `mode: "session"` ต้องใช้ `thread: true` - `"delete"` archive ทันทีหลังประกาศ (ยังคงเก็บ transcript ไว้ผ่านการเปลี่ยนชื่อ) + `"delete"` จะเก็บถาวรทันทีหลังประกาศ (ยังคงเก็บทรานสคริปต์ไว้ผ่านการเปลี่ยนชื่อ) - `require` ปฏิเสธการ spawn เว้นแต่ runtime ลูกเป้าหมายอยู่ใน sandbox + `require` ปฏิเสธการ spawn เว้นแต่ runtime ลูกเป้าหมายจะอยู่ใน sandbox - `fork` แตกกิ่ง transcript ปัจจุบันของผู้ร้องขอไปยังเซสชันลูก เอเจนต์ย่อยแบบ native เท่านั้น การ spawn ที่ผูกกับเธรดมีค่าเริ่มต้นเป็น `fork`; การ spawn ที่ไม่ใช่เธรดมีค่าเริ่มต้นเป็น `isolated` + `fork` แตกแขนงทรานสคริปต์ปัจจุบันของผู้ร้องขอเข้าสู่เซสชันลูก เฉพาะเอเจนต์ย่อยแบบ native เท่านั้น การ spawn ที่ผูกกับเธรดมีค่าเริ่มต้นเป็น `fork`; การ spawn ที่ไม่ใช่เธรดมีค่าเริ่มต้นเป็น `isolated` -`sessions_spawn` ไม่รับพารามิเตอร์การส่งมอบผ่านช่อง (`target`, -`channel`, `to`, `threadId`, `replyTo`, `transport`) สำหรับการส่งมอบ ให้ใช้ +`sessions_spawn` ไม่รับพารามิเตอร์การส่งผ่านช่องทาง (`target`, +`channel`, `to`, `threadId`, `replyTo`, `transport`) สำหรับการส่ง ให้ใช้ `message`/`sessions_send` จากการรันที่ spawn แล้ว ## เซสชันที่ผูกกับเธรด -เมื่อเปิดใช้งานการผูกเธรดสำหรับช่อง เอเจนต์ย่อยสามารถคงการผูกกับเธรดไว้ได้ -เพื่อให้ข้อความผู้ใช้ติดตามผลในเธรดนั้นยัง route ไปยังเซสชันเอเจนต์ย่อยเดียวกัน +เมื่อเปิดใช้งานการผูกเธรดสำหรับช่องทาง เอเจนต์ย่อยสามารถคงการผูก +กับเธรดไว้ เพื่อให้ข้อความผู้ใช้ติดตามผลในเธรดนั้นยังคงกำหนดเส้นทางไปยัง +เซสชันเอเจนต์ย่อยเดียวกัน -### ช่องที่รองรับเธรด +### ช่องทางที่รองรับเธรด -**Discord** เป็นช่องเดียวที่รองรับอยู่ในปัจจุบัน รองรับ -เซสชัน subagent แบบคงอยู่ที่ผูกกับเธรด (`sessions_spawn` พร้อม +**Discord** เป็นช่องทางเดียวที่รองรับในขณะนี้ รองรับ +เซสชันเอเจนต์ย่อยที่ผูกกับเธรดแบบถาวร (`sessions_spawn` พร้อม `thread: true`), การควบคุมเธรดด้วยตนเอง (`/focus`, `/unfocus`, `/agents`, -`/session idle`, `/session max-age`) และคีย์ adapter +`/session idle`, `/session max-age`) และคีย์อะแดปเตอร์ `channels.discord.threadBindings.enabled`, `channels.discord.threadBindings.idleHours`, -`channels.discord.threadBindings.maxAgeHours`, และ +`channels.discord.threadBindings.maxAgeHours` และ `channels.discord.threadBindings.spawnSessions` ### โฟลว์ด่วน - `sessions_spawn` พร้อม `thread: true` (และ `mode: "session"` แบบเลือกได้) + `sessions_spawn` พร้อม `thread: true` (และเลือกใส่ `mode: "session"` ได้) - OpenClaw สร้างหรือผูกเธรดกับ target ของเซสชันนั้นในช่องที่ใช้งานอยู่ + OpenClaw สร้างหรือผูกเธรดกับเป้าหมายเซสชันนั้นในช่องทางที่ใช้งานอยู่ - การตอบกลับและข้อความติดตามผลในเธรดนั้น route ไปยังเซสชันที่ผูกไว้ + การตอบกลับและข้อความติดตามผลในเธรดนั้นจะถูกส่งต่อไปยังเซสชันที่ผูกไว้ - ใช้ `/session idle` เพื่อตรวจสอบ/อัปเดต auto-unfocus เมื่อไม่มีความเคลื่อนไหว และ - `/session max-age` เพื่อควบคุม hard cap + ใช้ `/session idle` เพื่อตรวจสอบ/อัปเดตการเลิกโฟกัสอัตโนมัติเมื่อไม่มีความเคลื่อนไหว และ + `/session max-age` เพื่อควบคุมขีดจำกัดสูงสุดแบบตายตัว - ใช้ `/unfocus` เพื่อ detach ด้วยตนเอง + ใช้ `/unfocus` เพื่อแยกออกด้วยตนเอง ### การควบคุมด้วยตนเอง -| คำสั่ง | ผลลัพธ์ | +| คำสั่ง | ผลลัพธ์ | | ------------------ | --------------------------------------------------------------------- | -| `/focus ` | ผูกเธรดปัจจุบัน (หรือสร้างเธรดใหม่) เข้ากับเป้าหมายเอเจนต์ย่อย/เซสชัน | -| `/unfocus` | ลบการผูกสำหรับเธรดที่ถูกผูกอยู่ในปัจจุบัน | -| `/agents` | แสดงรายการงานที่ทำงานอยู่และสถานะการผูก (`thread:` หรือ `unbound`) | -| `/session idle` | ตรวจสอบ/อัปเดตการยกเลิกโฟกัสอัตโนมัติเมื่อไม่ได้ใช้งาน (เฉพาะเธรดที่ถูกผูกและโฟกัสอยู่) | -| `/session max-age` | ตรวจสอบ/อัปเดตขีดจำกัดสูงสุดแบบบังคับ (เฉพาะเธรดที่ถูกผูกและโฟกัสอยู่) | +| `/focus ` | ผูกเธรดปัจจุบัน (หรือสร้างใหม่) กับเป้าหมาย sub-agent/เซสชัน | +| `/unfocus` | ลบการผูกสำหรับเธรดที่ผูกอยู่ในปัจจุบัน | +| `/agents` | แสดงรายการรันที่ใช้งานอยู่และสถานะการผูก (`thread:` หรือ `unbound`) | +| `/session idle` | ตรวจสอบ/อัปเดตการเลิกโฟกัสอัตโนมัติเมื่อว่าง (เฉพาะเธรดที่ผูกและโฟกัสอยู่) | +| `/session max-age` | ตรวจสอบ/อัปเดตขีดจำกัดสูงสุดแบบตายตัว (เฉพาะเธรดที่ผูกและโฟกัสอยู่) | ### สวิตช์การกำหนดค่า -- **ค่าเริ่มต้นทั่วระบบ:** `session.threadBindings.enabled`, `session.threadBindings.idleHours`, `session.threadBindings.maxAgeHours`. -- **คีย์แทนที่ระดับช่องทางและคีย์ผูกอัตโนมัติเมื่อสร้าง** ขึ้นอยู่กับอะแดปเตอร์ ดู [ช่องทางที่รองรับเธรด](#thread-supporting-channels) ด้านบน +- **ค่าเริ่มต้นส่วนกลาง:** `session.threadBindings.enabled`, `session.threadBindings.idleHours`, `session.threadBindings.maxAgeHours` +- **คีย์สำหรับการเขียนทับตามช่องทางและการผูกอัตโนมัติเมื่อ spawn** ขึ้นอยู่กับ adapter แต่ละตัว ดู [ช่องทางที่รองรับเธรด](#thread-supporting-channels) ด้านบน ดู [ข้อมูลอ้างอิงการกำหนดค่า](/th/gateway/configuration-reference) และ -[คำสั่ง Slash](/th/tools/slash-commands) สำหรับรายละเอียดอะแดปเตอร์ปัจจุบัน +[คำสั่ง Slash](/th/tools/slash-commands) สำหรับรายละเอียด adapter ปัจจุบัน -### รายการที่อนุญาต +### Allowlist - รายการ ID เอเจนต์ที่สามารถกำหนดเป็นเป้าหมายผ่าน `agentId` แบบชัดเจน (`["*"]` อนุญาตทุกรายการ) ค่าเริ่มต้น: เฉพาะเอเจนต์ผู้ร้องขอ หากคุณตั้งค่ารายการและยังต้องการให้ผู้ร้องขอสร้างตัวเองด้วย `agentId` ให้ใส่ ID ของผู้ร้องขอไว้ในรายการ + รายการ agent ids ที่สามารถกำหนดเป็นเป้าหมายผ่าน `agentId` แบบชัดเจน (`["*"]` อนุญาตทุกตัว) ค่าเริ่มต้น: เฉพาะเอเจนต์ผู้ร้องขอเท่านั้น หากคุณตั้งค่ารายการและยังต้องการให้ผู้ร้องขอ spawn ตัวเองด้วย `agentId` ให้ใส่ id ของผู้ร้องขอในรายการด้วย - รายการเอเจนต์เป้าหมายเริ่มต้นที่อนุญาต ซึ่งใช้เมื่อเอเจนต์ผู้ร้องขอไม่ได้ตั้งค่า `subagents.allowAgents` ของตัวเอง + allowlist ของเอเจนต์เป้าหมายเริ่มต้นที่ใช้เมื่อเอเจนต์ผู้ร้องขอไม่ได้ตั้งค่า `subagents.allowAgents` ของตัวเอง - บล็อกการเรียก `sessions_spawn` ที่ละ `agentId` (บังคับให้เลือกโปรไฟล์อย่างชัดเจน) การแทนที่รายเอเจนต์: `agents.list[].subagents.requireAgentId` + บล็อกการเรียก `sessions_spawn` ที่ละ `agentId` (บังคับให้เลือกโปรไฟล์อย่างชัดเจน) การเขียนทับรายเอเจนต์: `agents.list[].subagents.requireAgentId` -หากเซสชันของผู้ร้องขออยู่ใน sandbox, `sessions_spawn` จะปฏิเสธเป้าหมาย -ที่จะทำงานแบบไม่อยู่ใน sandbox +หากเซสชันผู้ร้องขออยู่ใน sandbox, `sessions_spawn` จะปฏิเสธเป้าหมาย +ที่จะรันแบบไม่อยู่ใน sandbox -### การค้นหา +### การค้นพบ -ใช้ `agents_list` เพื่อดูว่า ID เอเจนต์ใดได้รับอนุญาตสำหรับ -`sessions_spawn` อยู่ในขณะนี้ การตอบกลับมีโมเดลที่มีผลจริงของเอเจนต์แต่ละรายการ -และเมทาดาทารันไทม์ที่ฝังอยู่ เพื่อให้ผู้เรียกแยกแยะ PI, เซิร์ฟเวอร์แอป Codex -และรันไทม์เนทีฟอื่นที่กำหนดค่าไว้ได้ +ใช้ `agents_list` เพื่อดูว่า agent ids ใดได้รับอนุญาตสำหรับ +`sessions_spawn` อยู่ในปัจจุบัน การตอบกลับจะรวมโมเดลที่มีผลจริงของแต่ละเอเจนต์ที่แสดง +และข้อมูลเมตารันไทม์แบบฝัง เพื่อให้ผู้เรียกแยกแยะ PI, Codex +app-server และ native runtimes อื่นที่กำหนดค่าไว้ได้ ### การเก็บถาวรอัตโนมัติ -- เซสชันเอเจนต์ย่อยจะถูกเก็บถาวรโดยอัตโนมัติหลังจาก `agents.defaults.subagents.archiveAfterMinutes` (ค่าเริ่มต้น `60`) +- เซสชัน sub-agent จะถูกเก็บถาวรโดยอัตโนมัติหลังจาก `agents.defaults.subagents.archiveAfterMinutes` (ค่าเริ่มต้น `60`) - การเก็บถาวรใช้ `sessions.delete` และเปลี่ยนชื่อทรานสคริปต์เป็น `*.deleted.` (โฟลเดอร์เดียวกัน) -- `cleanup: "delete"` จะเก็บถาวรทันทีหลังประกาศ (ยังคงเก็บทรานสคริปต์ไว้ผ่านการเปลี่ยนชื่อ) -- การเก็บถาวรอัตโนมัติเป็นแบบ best-effort; ตัวจับเวลาที่ค้างอยู่จะหายไปหาก Gateway รีสตาร์ท -- `runTimeoutSeconds` จะไม่เก็บถาวรอัตโนมัติ; จะหยุดเฉพาะงานที่ทำงานอยู่เท่านั้น เซสชันยังคงอยู่จนกว่าจะเก็บถาวรอัตโนมัติ -- การเก็บถาวรอัตโนมัติใช้กับเซสชันระดับความลึก 1 และระดับความลึก 2 เท่ากัน -- การล้างเบราว์เซอร์แยกจากการล้างการเก็บถาวร: แท็บ/โปรเซสของเบราว์เซอร์ที่ติดตามไว้จะถูกปิดแบบ best-effort เมื่องานทำงานเสร็จ แม้จะเก็บระเบียนทรานสคริปต์/เซสชันไว้ก็ตาม +- `cleanup: "delete"` จะเก็บถาวรทันทีหลังจากประกาศ (ยังคงเก็บทรานสคริปต์ไว้ผ่านการเปลี่ยนชื่อ) +- การเก็บถาวรอัตโนมัติเป็นแบบ best-effort; ตัวจับเวลาที่ค้างอยู่จะหายไปหาก gateway รีสตาร์ท +- `runTimeoutSeconds` จะ **ไม่** เก็บถาวรอัตโนมัติ; มันหยุดเฉพาะการรันเท่านั้น เซสชันจะยังคงอยู่จนกว่าจะเก็บถาวรอัตโนมัติ +- การเก็บถาวรอัตโนมัติใช้กับเซสชัน depth-1 และ depth-2 เท่ากัน +- การล้างข้อมูลเบราว์เซอร์แยกจากการล้างข้อมูลการเก็บถาวร: แท็บ/โปรเซสของเบราว์เซอร์ที่ติดตามไว้จะถูกปิดแบบ best-effort เมื่อการรันเสร็จสิ้น แม้จะยังเก็บระเบียนทรานสคริปต์/เซสชันไว้ก็ตาม -## เอเจนต์ย่อยแบบซ้อนกัน +## Sub-agents แบบซ้อน -ตามค่าเริ่มต้น เอเจนต์ย่อยไม่สามารถสร้างเอเจนต์ย่อยของตัวเองได้ -(`maxSpawnDepth: 1`) ตั้งค่า `maxSpawnDepth: 2` เพื่อเปิดใช้การซ้อนหนึ่งระดับ -นั่นคือ **รูปแบบตัวประสานงาน**: หลัก → เอเจนต์ย่อยตัวประสานงาน → -เอเจนต์ย่อยของเอเจนต์ย่อยที่เป็นผู้ปฏิบัติงาน +โดยค่าเริ่มต้น sub-agents ไม่สามารถ spawn sub-agents ของตัวเองได้ +(`maxSpawnDepth: 1`) ตั้งค่า `maxSpawnDepth: 2` เพื่อเปิดใช้งานการซ้อนหนึ่งระดับ +นั่นคือ **รูปแบบ orchestrator**: main → orchestrator sub-agent → +worker sub-sub-agents ```json5 { @@ -295,156 +309,154 @@ transcript ปัจจุบันอย่างชัดเจน ### ระดับความลึก -| ความลึก | รูปแบบคีย์เซสชัน | บทบาท | สร้างได้หรือไม่ | +| ความลึก | รูปแบบคีย์เซสชัน | บทบาท | Spawn ได้หรือไม่ | | ----- | -------------------------------------------- | --------------------------------------------- | ---------------------------- | -| 0 | `agent::main` | เอเจนต์หลัก | เสมอ | -| 1 | `agent::subagent:` | เอเจนต์ย่อย (ตัวประสานงานเมื่ออนุญาตความลึก 2) | เฉพาะเมื่อ `maxSpawnDepth >= 2` | -| 2 | `agent::subagent::subagent:` | เอเจนต์ย่อยของเอเจนต์ย่อย (ผู้ปฏิบัติงานปลายทาง) | ไม่เคย | +| 0 | `agent::main` | เอเจนต์หลัก | เสมอ | +| 1 | `agent::subagent:` | Sub-agent (orchestrator เมื่ออนุญาต depth 2) | เฉพาะเมื่อ `maxSpawnDepth >= 2` | +| 2 | `agent::subagent::subagent:` | Sub-sub-agent (worker ปลายทาง) | ไม่เคย | -### ลำดับการประกาศ +### สายการประกาศ -ผลลัพธ์ไหลย้อนกลับขึ้นตามลำดับ: +ผลลัพธ์จะไหลย้อนกลับขึ้นมาตามสาย: -1. ผู้ปฏิบัติงานระดับความลึก 2 เสร็จสิ้น → ประกาศไปยังพาเรนต์ของตัวเอง (ตัวประสานงานระดับความลึก 1) -2. ตัวประสานงานระดับความลึก 1 ได้รับประกาศ สังเคราะห์ผลลัพธ์ เสร็จสิ้น → ประกาศไปยังหลัก -3. เอเจนต์หลักได้รับประกาศและส่งให้ผู้ใช้ +1. Worker depth-2 เสร็จสิ้น → ประกาศไปยัง parent ของตัวเอง (orchestrator depth-1) +2. Orchestrator depth-1 ได้รับประกาศ สังเคราะห์ผลลัพธ์ เสร็จสิ้น → ประกาศไปยัง main +3. เอเจนต์หลักได้รับประกาศและส่งต่อให้ผู้ใช้ -แต่ละระดับเห็นเฉพาะประกาศจากลูกโดยตรงของตัวเองเท่านั้น +แต่ละระดับจะเห็นเฉพาะประกาศจาก children โดยตรงของตัวเองเท่านั้น -**คำแนะนำด้านการปฏิบัติการ:** เริ่มงานลูกหนึ่งครั้งและรอเหตุการณ์เสร็จสิ้น -แทนการสร้างลูปโพลรอบ `sessions_list`, -`sessions_history`, `/subagents list` หรือคำสั่ง sleep ของ `exec` -`sessions_list` และ `/subagents list` จะคงความสัมพันธ์เซสชันลูก -ให้โฟกัสกับงานสด ลูกที่ยังทำงานอยู่ยังคงแนบอยู่ ลูกที่จบแล้วจะยัง -มองเห็นได้ในหน้าต่างรายการล่าสุดช่วงสั้น ๆ และลิงก์ลูกที่มีเฉพาะในสโตร์และเก่าแล้วจะ -ถูกละเว้นหลังจากหน้าต่างความสดใหม่ของมัน วิธีนี้ป้องกันไม่ให้เมทาดาทา `spawnedBy` / -`parentSessionKey` เก่าชุบชีวิตลูกเงาหลัง -รีสตาร์ท หากเหตุการณ์เสร็จสิ้นของลูกมาถึงหลังจากคุณส่ง -คำตอบสุดท้ายแล้ว การติดตามผลที่ถูกต้องคือโทเคนเงียบตามตัวอักษร +**แนวทางปฏิบัติด้านการดำเนินงาน:** เริ่มงาน child เพียงครั้งเดียวและรอเหตุการณ์เสร็จสิ้น +แทนการสร้างลูป polling รอบ `sessions_list`, +`sessions_history`, `/subagents list` หรือคำสั่ง `exec` sleep +`sessions_list` และ `/subagents list` จะรักษาความสัมพันธ์ child-session +ให้โฟกัสอยู่กับงานที่ live อยู่ — children ที่ live จะยังคงแนบอยู่, children ที่จบแล้วจะยัง +มองเห็นได้ในหน้าต่างล่าสุดช่วงสั้น ๆ และลิงก์ child แบบมีเฉพาะใน store ที่เก่าจะถูก +ละเว้นหลังจากพ้นหน้าต่างความสดใหม่ การทำเช่นนี้ป้องกันไม่ให้ข้อมูลเมตาเก่า `spawnedBy` / +`parentSessionKey` ชุบชีวิต ghost children หลังจาก +รีสตาร์ท หากเหตุการณ์เสร็จสิ้นของ child มาถึงหลังจากคุณส่ง +คำตอบสุดท้ายไปแล้ว follow-up ที่ถูกต้องคือโทเค็นเงียบตามตัวอักษร `NO_REPLY` / `no_reply` ### นโยบายเครื่องมือตามความลึก -- บทบาทและขอบเขตการควบคุมถูกเขียนลงในเมทาดาทาเซสชันตอนสร้าง ซึ่งทำให้คีย์เซสชันแบบแบนหรือที่กู้คืนมาไม่สามารถได้สิทธิ์ตัวประสานงานกลับคืนโดยไม่ตั้งใจ -- **ความลึก 1 (ตัวประสานงาน เมื่อ `maxSpawnDepth >= 2`):** ได้รับ `sessions_spawn`, `subagents`, `sessions_list`, `sessions_history` เพื่อให้จัดการลูกของตัวเองได้ เครื่องมือเซสชัน/ระบบอื่นยังคงถูกปฏิเสธ -- **ความลึก 1 (ปลายทาง เมื่อ `maxSpawnDepth == 1`):** ไม่มีเครื่องมือเซสชัน (พฤติกรรมเริ่มต้นปัจจุบัน) -- **ความลึก 2 (ผู้ปฏิบัติงานปลายทาง):** ไม่มีเครื่องมือเซสชัน — `sessions_spawn` ถูกปฏิเสธเสมอที่ความลึก 2 ไม่สามารถสร้างลูกต่อได้ +- บทบาทและขอบเขตการควบคุมจะถูกเขียนลงในข้อมูลเมตาของเซสชันตอน spawn ซึ่งช่วยป้องกันไม่ให้คีย์เซสชันแบบแบนหรือที่กู้คืนมาได้รับสิทธิ์ orchestrator กลับมาโดยไม่ตั้งใจ +- **Depth 1 (orchestrator, เมื่อ `maxSpawnDepth >= 2`):** ได้รับ `sessions_spawn`, `subagents`, `sessions_list`, `sessions_history` เพื่อให้จัดการ children ของตัวเองได้ เครื่องมือ session/system อื่นยังคงถูกปฏิเสธ +- **Depth 1 (leaf, เมื่อ `maxSpawnDepth == 1`):** ไม่มีเครื่องมือเซสชัน (พฤติกรรมเริ่มต้นปัจจุบัน) +- **Depth 2 (leaf worker):** ไม่มีเครื่องมือเซสชัน — `sessions_spawn` จะถูกปฏิเสธเสมอที่ depth 2 ไม่สามารถ spawn children ต่อได้ -### ขีดจำกัดการสร้างรายเอเจนต์ +### ขีดจำกัดการ spawn รายเอเจนต์ -แต่ละเซสชันเอเจนต์ (ทุกระดับความลึก) มีลูกที่ทำงานอยู่ได้สูงสุด `maxChildrenPerAgent` -(ค่าเริ่มต้น `5`) ในแต่ละครั้ง วิธีนี้ป้องกันการกระจายงานเกินควบคุม -จากตัวประสานงานเดียว +เซสชันเอเจนต์แต่ละรายการ (ที่ความลึกใดก็ได้) สามารถมี children ที่ใช้งานอยู่ได้สูงสุด `maxChildrenPerAgent` +(ค่าเริ่มต้น `5`) พร้อมกัน การตั้งค่านี้ป้องกัน fan-out ที่ควบคุมไม่ได้ +จาก orchestrator เดียว -### การหยุดแบบลูกโซ่ +### การหยุดแบบ cascade -การหยุดตัวประสานงานระดับความลึก 1 จะหยุดลูกระดับความลึก 2 -ทั้งหมดของมันโดยอัตโนมัติ: +การหยุด orchestrator depth-1 จะหยุด children depth-2 ทั้งหมดของมันโดยอัตโนมัติ: -- `/stop` ในแชตหลักหยุดเอเจนต์ระดับความลึก 1 ทั้งหมดและหยุดแบบลูกโซ่ไปยังลูกระดับความลึก 2 ของพวกเขา -- `/subagents kill ` หยุดเอเจนต์ย่อยที่ระบุและหยุดแบบลูกโซ่ไปยังลูกของมัน -- `/subagents kill all` หยุดเอเจนต์ย่อยทั้งหมดสำหรับผู้ร้องขอและหยุดแบบลูกโซ่ +- `/stop` ในแชตหลักจะหยุดเอเจนต์ depth-1 ทั้งหมดและ cascade ไปยัง children depth-2 ของพวกเขา +- `/subagents kill ` หยุด sub-agent เฉพาะตัวและ cascade ไปยัง children ของมัน +- `/subagents kill all` หยุด sub-agents ทั้งหมดสำหรับผู้ร้องขอและ cascade ## การยืนยันตัวตน -การยืนยันตัวตนของเอเจนต์ย่อยถูกแก้ตาม **ID เอเจนต์** ไม่ใช่ตามประเภทเซสชัน: +การยืนยันตัวตนของ sub-agent จะ resolve ตาม **agent id** ไม่ใช่ตามประเภทเซสชัน: -- คีย์เซสชันเอเจนต์ย่อยคือ `agent::subagent:` -- สโตร์การยืนยันตัวตนถูกโหลดจาก `agentDir` ของเอเจนต์นั้น -- โปรไฟล์การยืนยันตัวตนของเอเจนต์หลักถูกผสานเข้าเป็น **fallback**; โปรไฟล์เอเจนต์จะแทนที่โปรไฟล์หลักเมื่อมีข้อขัดแย้ง +- คีย์เซสชัน sub-agent คือ `agent::subagent:` +- auth store โหลดจาก `agentDir` ของเอเจนต์นั้น +- auth profiles ของเอเจนต์หลักจะถูกผสานเข้ามาเป็น **fallback**; โปรไฟล์ของเอเจนต์จะเขียนทับโปรไฟล์หลักเมื่อมี conflict -การผสานเป็นแบบเพิ่มเข้าไป ดังนั้นโปรไฟล์หลักจึงพร้อมใช้งานเป็น -fallback เสมอ ยังไม่รองรับการยืนยันตัวตนแบบแยกขาดต่อเอเจนต์อย่างสมบูรณ์ +การผสานเป็นแบบเพิ่มเข้ามา ดังนั้นโปรไฟล์หลักจะพร้อมใช้งานเป็น +fallback เสมอ ยังไม่รองรับ auth ที่แยกอย่างสมบูรณ์ต่อเอเจนต์ ## การประกาศ -เอเจนต์ย่อยรายงานกลับผ่านขั้นตอนประกาศ: +Sub-agents รายงานกลับผ่านขั้นตอนการประกาศ: -- ขั้นตอนประกาศทำงานภายในเซสชันเอเจนต์ย่อย (ไม่ใช่เซสชันผู้ร้องขอ) -- หากเอเจนต์ย่อยตอบกลับตรงกับ `ANNOUNCE_SKIP` จะไม่มีการโพสต์อะไร -- หากข้อความผู้ช่วยล่าสุดเป็นโทเคนเงียบตรงตัว `NO_REPLY` / `no_reply` เอาต์พุตประกาศจะถูกระงับ แม้จะเคยมีความคืบหน้าที่มองเห็นได้ก่อนหน้านั้น +- ขั้นตอนการประกาศรันภายในเซสชัน sub-agent (ไม่ใช่เซสชันผู้ร้องขอ) +- หาก sub-agent ตอบกลับตรงกับ `ANNOUNCE_SKIP` จะไม่มีการโพสต์อะไร +- หากข้อความ assistant ล่าสุดเป็นโทเค็นเงียบตรงตามตัวอักษร `NO_REPLY` / `no_reply` เอาต์พุตประกาศจะถูกระงับแม้ก่อนหน้านี้จะมีความคืบหน้าที่มองเห็นได้ การส่งมอบขึ้นอยู่กับความลึกของผู้ร้องขอ: -- เซสชันผู้ร้องขอระดับบนสุดใช้การเรียก `agent` แบบติดตามผลพร้อมการส่งมอบภายนอก (`deliver=true`) -- เซสชันเอเจนต์ย่อยผู้ร้องขอแบบซ้อนกันจะได้รับการฉีดติดตามผลภายใน (`deliver=false`) เพื่อให้ตัวประสานงานสังเคราะห์ผลลัพธ์ลูกภายในเซสชันได้ -- หากเซสชันเอเจนต์ย่อยผู้ร้องขอแบบซ้อนกันหายไป OpenClaw จะ fallback ไปยังผู้ร้องขอของเซสชันนั้นเมื่อมี +- เซสชันผู้ร้องขอระดับบนสุดใช้การเรียก `agent` แบบ follow-up พร้อมการส่งมอบภายนอก (`deliver=true`) +- เซสชัน requester subagent แบบซ้อนจะได้รับการฉีด follow-up ภายใน (`deliver=false`) เพื่อให้ orchestrator สังเคราะห์ผลลัพธ์ child ภายในเซสชันได้ +- หากเซสชัน nested requester subagent หายไป OpenClaw จะ fallback ไปยังผู้ร้องขอของเซสชันนั้นเมื่อมี -สำหรับเซสชันผู้ร้องขอระดับบนสุด การส่งมอบโดยตรงในโหมดเสร็จสิ้นจะ -แก้เส้นทางบทสนทนา/เธรดที่ถูกผูกและการแทนที่ของ hook ก่อน จากนั้นเติม -ฟิลด์เป้าหมายช่องทางที่หายไปจากเส้นทางที่เซสชันผู้ร้องขอเก็บไว้ -วิธีนี้ทำให้การเสร็จสิ้นอยู่ในแชต/หัวข้อที่ถูกต้อง แม้ต้นทางการเสร็จสิ้น +สำหรับเซสชันผู้ร้องขอระดับบนสุด การส่งมอบโดยตรงใน completion-mode จะ +resolve เส้นทาง conversation/thread ที่ผูกอยู่และ hook override ก่อน จากนั้นเติม +ฟิลด์ channel-target ที่ขาดจากเส้นทางที่จัดเก็บไว้ของเซสชันผู้ร้องขอ +ซึ่งทำให้ completion อยู่ในแชต/หัวข้อที่ถูกต้อง แม้ต้นทาง completion จะระบุเฉพาะช่องทางก็ตาม -การรวมผลการเสร็จสิ้นของลูกถูกจำกัดขอบเขตไว้ที่งานผู้ร้องขอปัจจุบันเมื่อ -สร้างข้อค้นพบการเสร็จสิ้นแบบซ้อนกัน เพื่อป้องกันไม่ให้เอาต์พุตลูกจากงานก่อนหน้า -ที่เก่าแล้วรั่วไหลเข้าไปในการประกาศปัจจุบัน การตอบกลับประกาศจะคง -การกำหนดเส้นทางเธรด/หัวข้อเมื่อมีในอะแดปเตอร์ช่องทาง +การรวบรวม completion ของ child จะถูกจำกัดขอบเขตไว้ที่การรันผู้ร้องขอปัจจุบันเมื่อ +สร้าง findings ของ nested completion เพื่อป้องกันไม่ให้เอาต์พุต child +จากการรันก่อนหน้าที่เก่ารั่วเข้ามาในประกาศปัจจุบัน การตอบกลับประกาศจะรักษา +การกำหนดเส้นทาง thread/topic เมื่อมีใน channel adapters -### บริบทประกาศ +### บริบทการประกาศ -บริบทประกาศถูกทำให้เป็นมาตรฐานเป็นบล็อกเหตุการณ์ภายในที่เสถียร: +บริบทการประกาศจะถูกทำให้เป็นมาตรฐานเป็นบล็อกเหตุการณ์ภายในที่เสถียร: -| ฟิลด์ | แหล่งที่มา | +| ฟิลด์ | แหล่งที่มา | | -------------- | ------------------------------------------------------------------------------------------------------------- | -| แหล่งที่มา | `subagent` หรือ `cron` | -| ID เซสชัน | คีย์/ID เซสชันลูก | -| ประเภท | ประเภทประกาศ + ป้ายกำกับงาน | -| สถานะ | ได้จากผลลัพธ์รันไทม์ (`success`, `error`, `timeout` หรือ `unknown`) — **ไม่ได้** อนุมานจากข้อความโมเดล | -| เนื้อหาผลลัพธ์ | ข้อความผู้ช่วยล่าสุดที่มองเห็นได้ มิฉะนั้นเป็นข้อความ tool/toolResult ล่าสุดที่ผ่านการทำให้ปลอดภัยแล้ว | -| การติดตามผล | คำแนะนำที่อธิบายว่าเมื่อใดควรตอบกลับหรือคงความเงียบ | +| Source | `subagent` หรือ `cron` | +| Session ids | คีย์/id เซสชัน child | +| Type | ประเภทประกาศ + ป้ายกำกับงาน | +| Status | ได้มาจากผลลัพธ์รันไทม์ (`success`, `error`, `timeout` หรือ `unknown`) — **ไม่ได้** อนุมานจากข้อความโมเดล | +| Result content | ข้อความ assistant ล่าสุดที่มองเห็นได้ มิฉะนั้นคือข้อความ tool/toolResult ล่าสุดที่ผ่านการ sanitize แล้ว | +| Follow-up | คำสั่งที่อธิบายว่าเมื่อใดควรตอบกลับเทียบกับอยู่เงียบ | -งานที่ล้มเหลวในสถานะปลายทางจะรายงานสถานะล้มเหลวโดยไม่เล่นซ้ำข้อความตอบกลับ -ที่จับไว้ เมื่อ timeout หากลูกผ่านไปได้เพียงการเรียกเครื่องมือ ประกาศ -สามารถยุบประวัตินั้นเป็นสรุปความคืบหน้าบางส่วนแบบสั้น -แทนการเล่นเอาต์พุตเครื่องมือดิบซ้ำ +การรัน terminal ที่ล้มเหลวจะรายงานสถานะความล้มเหลวโดยไม่ replay +ข้อความตอบกลับที่จับไว้ เมื่อ timeout หาก child ไปถึงแค่การเรียกเครื่องมือ +ประกาศสามารถยุบประวัตินั้นเป็นสรุปความคืบหน้าบางส่วนแบบสั้น +แทนการ replay เอาต์พุตเครื่องมือดิบ ### บรรทัดสถิติ -เพย์โหลดประกาศมีบรรทัดสถิติที่ท้ายสุด (แม้ถูกห่อบรรทัด): +Payload ประกาศจะมีบรรทัดสถิติท้ายสุด (แม้เมื่อถูกครอบไว้): -- รันไทม์ (เช่น `runtime 5m12s`) -- การใช้โทเคน (อินพุต/เอาต์พุต/ทั้งหมด) -- ค่าใช้จ่ายประมาณการเมื่อกำหนดราคาของโมเดลไว้ (`models.providers.*.models[].cost`) -- `sessionKey`, `sessionId` และเส้นทางทรานสคริปต์ เพื่อให้เอเจนต์หลักดึงประวัติผ่าน `sessions_history` หรือตรวจสอบไฟล์บนดิสก์ได้ +- Runtime (เช่น `runtime 5m12s`) +- การใช้โทเค็น (input/output/total) +- ค่าใช้จ่ายโดยประมาณเมื่อกำหนดราคาของโมเดลไว้ (`models.providers.*.models[].cost`) +- `sessionKey`, `sessionId` และเส้นทางทรานสคริปต์ เพื่อให้เอเจนต์หลักสามารถดึงประวัติผ่าน `sessions_history` หรือตรวจสอบไฟล์บนดิสก์ได้ -เมทาดาทาภายในมีไว้สำหรับการประสานงานเท่านั้น การตอบกลับที่แสดงต่อผู้ใช้ -ควรเขียนใหม่ด้วยเสียงผู้ช่วยตามปกติ +ข้อมูลเมตาภายในมีไว้สำหรับ orchestration เท่านั้น; คำตอบที่ผู้ใช้เห็น +ควรถูกเขียนใหม่ด้วยน้ำเสียง assistant ปกติ -### เหตุใดจึงควรใช้ `sessions_history` +### เหตุผลที่ควรใช้ `sessions_history` -`sessions_history` เป็นเส้นทางการประสานงานที่ปลอดภัยกว่า: +`sessions_history` เป็นเส้นทาง orchestration ที่ปลอดภัยกว่า: -- การเรียกคืนของผู้ช่วยถูกทำให้เป็นมาตรฐานก่อน: ลบแท็กการคิด; ลบโครง `` / ``; ลบบล็อกเพย์โหลด XML การเรียกเครื่องมือแบบข้อความธรรมดา (``, ``, ``, ``) รวมถึงเพย์โหลดที่ถูกตัดทอนและไม่เคยปิดอย่างเรียบร้อย; ลบโครง tool-call/result ที่ถูกลดระดับและมาร์กเกอร์บริบทประวัติ; ลบโทเคนควบคุมโมเดลที่รั่ว (`<|assistant|>`, ASCII `<|...|>` อื่น, แบบเต็มความกว้าง `<|...|>`); ลบ XML การเรียกเครื่องมือ MiniMax ที่มีรูปแบบผิด -- ข้อความที่ดูเหมือนข้อมูลประจำตัว/โทเคนจะถูกปกปิด +- การเรียกคืนของ assistant จะถูกทำให้เป็นมาตรฐานก่อน: ลบ thinking tags; ลบโครง `` / ``; ลบบล็อก payload XML ของการเรียกเครื่องมือแบบ plain-text (``, ``, ``, ``) รวมถึง payload ที่ถูกตัดทอนซึ่งไม่เคยปิดอย่างสมบูรณ์; ลบโครง tool-call/result ที่ถูกลดระดับและตัวทำเครื่องหมาย historical-context; ลบ model control tokens ที่รั่ว (`<|assistant|>`, ASCII `<|...|>` อื่น, full-width `<|...|>`); ลบ XML tool-call ของ MiniMax ที่ malformed +- ข้อความที่ดูเหมือน credential/token จะถูก redact - บล็อกยาวสามารถถูกตัดทอนได้ - ประวัติขนาดใหญ่มากสามารถทิ้งแถวเก่ากว่า หรือแทนที่แถวที่ใหญ่เกินด้วย `[sessions_history omitted: message too large]` -- การตรวจสอบทรานสคริปต์ดิบบนดิสก์เป็น fallback เมื่อคุณต้องการทรานสคริปต์เต็มแบบตรงทุกไบต์ +- การตรวจสอบทรานสคริปต์ดิบบนดิสก์คือ fallback เมื่อคุณต้องการทรานสคริปต์แบบ byte-for-byte ครบถ้วน ## นโยบายเครื่องมือ -เอเจนต์ย่อยใช้โปรไฟล์และไปป์ไลน์นโยบายเครื่องมือเดียวกับพาเรนต์หรือ -เอเจนต์เป้าหมายก่อน หลังจากนั้น OpenClaw จะใช้เลเยอร์ข้อจำกัด -เอเจนต์ย่อย +Sub-agent ใช้โปรไฟล์และไปป์ไลน์นโยบายเครื่องมือเดียวกับ agent หลักหรือ +agent เป้าหมายก่อน จากนั้น OpenClaw จะใช้ชั้นข้อจำกัดของ sub-agent -เมื่อไม่มี `tools.profile` ที่จำกัด เอเจนต์ย่อยจะได้รับ **เครื่องมือทั้งหมด ยกเว้น -เครื่องมือเซสชัน** และเครื่องมือระบบ: +เมื่อไม่มี `tools.profile` ที่จำกัด sub-agent จะได้รับ **เครื่องมือทั้งหมด ยกเว้น +เครื่องมือ session** และเครื่องมือระบบ: - `sessions_list` - `sessions_history` - `sessions_send` - `sessions_spawn` -`sessions_history` ยังคงเป็นมุมมองการเรียกคืนที่มีขอบเขตและผ่านการทำให้ปลอดภัยที่นี่ด้วย — -ไม่ใช่การดัมป์ทรานสคริปต์ดิบ +`sessions_history` ยังคงเป็นมุมมองการเรียกคืนที่มีขอบเขตและผ่านการทำให้ปลอดภัยแล้วในที่นี้ด้วย — +ไม่ใช่การดัมป์ transcript ดิบ -เมื่อ `maxSpawnDepth >= 2` เอเจนต์ย่อยตัวประสานงานระดับความลึก 1 จะได้รับ +เมื่อ `maxSpawnDepth >= 2` sub-agent ตัว orchestrator ที่ depth-1 จะได้รับ `sessions_spawn`, `subagents`, `sessions_list` และ -`sessions_history` เพิ่มเติม เพื่อให้จัดการลูกของตัวเองได้ +`sessions_history` เพิ่มเติม เพื่อให้สามารถจัดการลูกของตนได้ -### แทนที่ผ่านการกำหนดค่า +### Override ผ่าน config ```json5 { @@ -468,12 +480,12 @@ fallback เสมอ ยังไม่รองรับการยืนย } ``` -`tools.subagents.tools.allow` เป็นตัวกรอง allow-only ขั้นสุดท้าย สามารถจำกัด +`tools.subagents.tools.allow` เป็นตัวกรอง allow-only ขั้นสุดท้าย มันสามารถจำกัด ชุดเครื่องมือที่ resolve แล้วให้แคบลงได้ แต่ไม่สามารถ **เพิ่มกลับ** เครื่องมือที่ถูกนำออก โดย `tools.profile` ได้ ตัวอย่างเช่น `tools.profile: "coding"` รวม -`web_search`/`web_fetch` แต่ไม่รวมเครื่องมือ `browser` หากต้องการให้ -sub-agent ที่ใช้ profile แบบ coding ใช้ระบบอัตโนมัติของเบราว์เซอร์ได้ ให้เพิ่ม browser ใน -ขั้น profile: +`web_search`/`web_fetch` แต่ไม่มีเครื่องมือ `browser` หากต้องการให้ +sub-agent ในโปรไฟล์ coding ใช้การทำงานอัตโนมัติของ browser ให้เพิ่ม browser ใน +ขั้นโปรไฟล์: ```json5 { @@ -484,65 +496,64 @@ sub-agent ที่ใช้ profile แบบ coding ใช้ระบบอ } ``` -ใช้ `agents.list[].tools.alsoAllow: ["browser"]` แบบรายเอเจนต์เมื่อมีเพียง -เอเจนต์เดียวที่ควรได้รับระบบอัตโนมัติของเบราว์เซอร์ +ใช้ `agents.list[].tools.alsoAllow: ["browser"]` แบบราย agent เมื่อมีเพียง +agent เดียวที่ควรได้รับการทำงานอัตโนมัติของ browser -## ภาวะพร้อมกัน +## การทำงานพร้อมกัน -Sub-agent ใช้ lane คิวในโปรเซสเฉพาะ: +Sub-agent ใช้ lane คิวในโปรเซสโดยเฉพาะ: - **ชื่อ lane:** `subagent` -- **ภาวะพร้อมกัน:** `agents.defaults.subagents.maxConcurrent` (ค่าเริ่มต้น `8`) +- **การทำงานพร้อมกัน:** `agents.defaults.subagents.maxConcurrent` (ค่าเริ่มต้น `8`) -## สถานะมีชีวิตและการกู้คืน +## Liveness และการกู้คืน OpenClaw ไม่ถือว่าการไม่มี `endedAt` เป็นหลักฐานถาวรว่า -sub-agent ยังมีชีวิตอยู่ การรันที่ยังไม่จบซึ่งเก่ากว่าหน้าต่าง stale-run -จะหยุดนับเป็น active/pending ใน `/subagents list`, สรุปสถานะ, -gating การเสร็จสมบูรณ์ของ descendant และการตรวจสอบภาวะพร้อมกันต่อ session +sub-agent ยังทำงานอยู่ run ที่ยังไม่สิ้นสุดซึ่งเก่ากว่าหน้าต่าง stale-run +จะหยุดถูกนับเป็น active/pending ใน `/subagents list`, สรุปสถานะ, +การ gating การเสร็จสิ้นของ descendant และการตรวจสอบ concurrency แบบราย session -หลังจาก Gateway รีสตาร์ต การรันที่ restore แล้วแต่ stale และยังไม่จบจะถูกตัดทิ้ง เว้นแต่ -session ลูกของการรันนั้นจะถูกทำเครื่องหมาย `abortedLastRun: true` session ลูกที่ -ถูกยกเลิกจากการรีสตาร์ตเหล่านั้นยังสามารถกู้คืนได้ผ่านโฟลว์กู้คืน orphan ของ sub-agent -ซึ่งจะส่งข้อความ resume สังเคราะห์ก่อน -ล้างเครื่องหมาย aborted +หลังจาก Gateway restart แล้ว run ที่ restore กลับมาและยังไม่สิ้นสุดซึ่ง stale จะถูก prune เว้นแต่ +child session ของมันถูกทำเครื่องหมาย `abortedLastRun: true` child session ที่ +restart-aborted เหล่านั้นยังคงกู้คืนได้ผ่าน flow การกู้คืน orphan ของ sub-agent +ซึ่งส่งข้อความ resume สังเคราะห์ก่อนล้าง marker ที่ถูก aborted -การกู้คืนอัตโนมัติหลังรีสตาร์ตถูกจำกัดต่อ session ลูก หาก -sub-agent ลูกตัวเดิมถูกยอมรับให้กู้คืน orphan ซ้ำ ๆ ภายใน -หน้าต่าง rapid re-wedge OpenClaw จะบันทึก recovery tombstone ใน -session นั้นและหยุด auto-resume ให้ในการรีสตาร์ตภายหลัง รัน -`openclaw tasks maintenance --apply` เพื่อ reconcile task record หรือ -`openclaw doctor --fix` เพื่อล้าง flag การกู้คืน aborted ที่ stale บน +การกู้คืนอัตโนมัติหลัง restart ถูกจำกัดแบบราย child session หาก child ของ +sub-agent เดียวกันถูกยอมรับสำหรับการกู้คืน orphan ซ้ำ ๆ ภายใน +หน้าต่าง rapid re-wedge OpenClaw จะคง recovery tombstone ไว้บน +session นั้น และหยุด auto-resume มันในการ restart ภายหลัง ให้รัน +`openclaw tasks maintenance --apply` เพื่อ reconcile ระเบียน task หรือ +`openclaw doctor --fix` เพื่อล้าง flag การกู้คืนที่ aborted และ stale บน session ที่ถูก tombstone หากการ spawn sub-agent ล้มเหลวด้วย Gateway `PAIRING_REQUIRED` / `scope-upgrade` ให้ตรวจสอบ RPC caller ก่อนแก้ไขสถานะ pairing การประสานงาน `sessions_spawn` ภายในควรเชื่อมต่อเป็น -`client.id: "gateway-client"` พร้อม `client.mode: "backend"` ผ่าน auth แบบ -direct loopback shared-token/password เส้นทางนั้นไม่ขึ้นกับ -scope baseline ของ paired-device ของ CLI ผู้เรียกจากระยะไกล, -`deviceIdentity` แบบ explicit, เส้นทาง device-token แบบ explicit และไคลเอนต์ -browser/node ยังต้องได้รับการอนุมัติ device ตามปกติสำหรับ scope upgrade +`client.id: "gateway-client"` พร้อม `client.mode: "backend"` ผ่าน +การ auth แบบ shared-token/password โดยตรงบน local loopback; เส้นทางนั้นไม่ขึ้นกับ +baseline scope ของอุปกรณ์ที่จับคู่แล้วของ CLI caller ระยะไกล, +`deviceIdentity` แบบระบุชัดเจน, เส้นทาง device-token แบบระบุชัดเจน และ client แบบ browser/node +ยังต้องได้รับการอนุมัติอุปกรณ์ตามปกติสำหรับการอัปเกรด scope ## การหยุด -- การส่ง `/stop` ในแชต requester จะยกเลิก session ของ requester และหยุดการรัน sub-agent ที่ active ใด ๆ ที่ spawn จาก session นั้น โดย cascade ไปยังลูกซ้อน -- `/subagents kill ` หยุด sub-agent เฉพาะตัวและ cascade ไปยังลูกของมัน +- การส่ง `/stop` ในแชตของ requester จะ abort session ของ requester และหยุด run ของ sub-agent ที่ active ทั้งหมดที่ spawn จาก session นั้น โดย cascade ไปยังลูกที่ซ้อนอยู่ +- `/subagents kill ` หยุด sub-agent ที่ระบุและ cascade ไปยังลูกของมัน ## ข้อจำกัด -- การ announce ของ sub-agent เป็นแบบ **best-effort** หาก Gateway รีสตาร์ต งาน "announce back" ที่ pending จะสูญหาย -- Sub-agent ยังคงใช้ทรัพยากรของโปรเซส Gateway เดียวกัน ให้ถือว่า `maxConcurrent` เป็นวาล์วนิรภัย -- `sessions_spawn` เป็น non-blocking เสมอ: จะคืน `{ status: "accepted", runId, childSessionKey }` ทันที -- context ของ sub-agent inject เฉพาะ `AGENTS.md` + `TOOLS.md` (ไม่มี `SOUL.md`, `IDENTITY.md`, `USER.md`, `HEARTBEAT.md` หรือ `BOOTSTRAP.md`) -- ความลึกการซ้อนสูงสุดคือ 5 (`maxSpawnDepth` range: 1–5) แนะนำให้ใช้ความลึก 2 สำหรับกรณีใช้งานส่วนใหญ่ -- `maxChildrenPerAgent` จำกัดจำนวนลูกที่ active ต่อ session (ค่าเริ่มต้น `5`, range `1–20`) +- การประกาศของ sub-agent เป็นแบบ **best-effort** หาก gateway restart งาน "announce back" ที่ค้างอยู่จะหายไป +- Sub-agent ยังใช้ทรัพยากรของโปรเซส gateway เดียวกันร่วมกัน ให้ถือว่า `maxConcurrent` เป็นวาล์วนิรภัย +- `sessions_spawn` เป็นแบบไม่ block เสมอ: มันส่งคืน `{ status: "accepted", runId, childSessionKey }` ทันที +- Context ของ sub-agent inject เฉพาะ `AGENTS.md` + `TOOLS.md` (ไม่มี `SOUL.md`, `IDENTITY.md`, `USER.md`, `HEARTBEAT.md` หรือ `BOOTSTRAP.md`) +- ความลึกการซ้อนสูงสุดคือ 5 (ช่วง `maxSpawnDepth`: 1–5) แนะนำให้ใช้ depth 2 สำหรับกรณีใช้งานส่วนใหญ่ +- `maxChildrenPerAgent` จำกัดจำนวนลูกที่ active ต่อ session (ค่าเริ่มต้น `5`, ช่วง `1–20`) ## ที่เกี่ยวข้อง - [ACP agents](/th/tools/acp-agents) - [Agent send](/th/tools/agent-send) -- [งานเบื้องหลัง](/th/automation/tasks) -- [เครื่องมือ sandbox แบบหลายเอเจนต์](/th/tools/multi-agent-sandbox-tools) +- [Background tasks](/th/automation/tasks) +- [Multi-agent sandbox tools](/th/tools/multi-agent-sandbox-tools) diff --git a/docs/th/web/control-ui.md b/docs/th/web/control-ui.md index 73e6771ac..5f129fc41 100644 --- a/docs/th/web/control-ui.md +++ b/docs/th/web/control-ui.md @@ -1,46 +1,46 @@ --- read_when: - คุณต้องการใช้งาน Gateway จากเบราว์เซอร์ - - คุณต้องการเข้าถึง Tailnet โดยไม่ใช้อุโมงค์ SSH + - คุณต้องการเข้าถึง Tailnet โดยไม่ต้องใช้อุโมงค์ SSH sidebarTitle: Control UI -summary: UI ควบคุมที่ทำงานบนเบราว์เซอร์สำหรับ Gateway (แชท, โหนด, การกำหนดค่า) -title: อินเทอร์เฟซควบคุม +summary: อินเทอร์เฟซควบคุมบนเบราว์เซอร์สำหรับ Gateway (แชท, โหนด, การกำหนดค่า) +title: ส่วนติดต่อผู้ใช้สำหรับควบคุม x-i18n: - generated_at: "2026-05-04T02:28:08Z" + generated_at: "2026-05-04T07:07:44Z" model: gpt-5.5 provider: openai - source_hash: c890d83da2c296b600e4b5a00a538f37e6bd54da31fbe62113ecd6177b15626e + source_hash: 07fbbe1c7fec5f67a04a231e02bdf0f7d16be9c5fe188915674d71fcd69002a5 source_path: web/control-ui.md workflow: 16 --- -UI ควบคุมเป็นแอปหน้าเดียวขนาดเล็กแบบ **Vite + Lit** ที่ให้บริการโดย Gateway: +Control UI เป็นแอปหน้าเดียวขนาดเล็กแบบ **Vite + Lit** ที่ให้บริการโดย Gateway: - ค่าเริ่มต้น: `http://:18789/` -- คำนำหน้าแบบไม่บังคับ: ตั้งค่า `gateway.controlUi.basePath` (เช่น `/openclaw`) +- คำนำหน้าแบบเลือกได้: ตั้งค่า `gateway.controlUi.basePath` (เช่น `/openclaw`) แอปนี้สื่อสาร **โดยตรงกับ Gateway WebSocket** บนพอร์ตเดียวกัน -## เปิดใช้งานด่วน (ภายในเครื่อง) +## เปิดอย่างรวดเร็ว (ภายในเครื่อง) หาก Gateway กำลังทำงานอยู่บนคอมพิวเตอร์เครื่องเดียวกัน ให้เปิด: - [http://127.0.0.1:18789/](http://127.0.0.1:18789/) (หรือ [http://localhost:18789/](http://localhost:18789/)) -หากหน้าเว็บโหลดไม่สำเร็จ ให้เริ่ม Gateway ก่อน: `openclaw gateway` +หากหน้าโหลดไม่สำเร็จ ให้เริ่ม Gateway ก่อน: `openclaw gateway` -การยืนยันตัวตนถูกส่งระหว่าง WebSocket handshake ผ่าน: +มีการส่ง Auth ระหว่างการจับมือ WebSocket ผ่าน: - `connect.params.auth.token` - `connect.params.auth.password` -- ส่วนหัวข้อมูลประจำตัวของ Tailscale Serve เมื่อ `gateway.auth.allowTailscale: true` -- ส่วนหัวข้อมูลประจำตัวของพร็อกซีที่เชื่อถือได้เมื่อ `gateway.auth.mode: "trusted-proxy"` +- ส่วนหัวตัวตนของ Tailscale Serve เมื่อ `gateway.auth.allowTailscale: true` +- ส่วนหัวตัวตนของพร็อกซีที่เชื่อถือได้เมื่อ `gateway.auth.mode: "trusted-proxy"` -แผงการตั้งค่าแดชบอร์ดจะเก็บ token สำหรับเซสชันแท็บเบราว์เซอร์ปัจจุบันและ URL Gateway ที่เลือกไว้ ส่วนรหัสผ่านจะไม่ถูกจัดเก็บไว้ โดยปกติ onboarding จะสร้าง gateway token สำหรับการยืนยันตัวตนแบบความลับร่วมเมื่อเชื่อมต่อครั้งแรก แต่การยืนยันตัวตนด้วยรหัสผ่านก็ใช้งานได้เช่นกันเมื่อ `gateway.auth.mode` เป็น `"password"` +แผงการตั้งค่าแดชบอร์ดจะเก็บโทเค็นสำหรับเซสชันแท็บเบราว์เซอร์ปัจจุบันและ URL Gateway ที่เลือกไว้ ส่วนรหัสผ่านจะไม่ถูกจัดเก็บ Onboarding มักสร้างโทเค็น Gateway สำหรับ Auth แบบ shared-secret เมื่อเชื่อมต่อครั้งแรก แต่ Auth ด้วยรหัสผ่านก็ใช้งานได้เช่นกันเมื่อ `gateway.auth.mode` เป็น `"password"` ## การจับคู่อุปกรณ์ (การเชื่อมต่อครั้งแรก) -เมื่อคุณเชื่อมต่อกับ UI ควบคุมจากเบราว์เซอร์หรืออุปกรณ์ใหม่ โดยปกติ Gateway จะต้องมี **การอนุมัติการจับคู่แบบครั้งเดียว** นี่เป็นมาตรการรักษาความปลอดภัยเพื่อป้องกันการเข้าถึงโดยไม่ได้รับอนุญาต +เมื่อคุณเชื่อมต่อกับ Control UI จากเบราว์เซอร์หรืออุปกรณ์ใหม่ โดยปกติ Gateway จะต้องมี **การอนุมัติการจับคู่แบบครั้งเดียว** นี่เป็นมาตรการด้านความปลอดภัยเพื่อป้องกันการเข้าถึงโดยไม่ได้รับอนุญาต **สิ่งที่คุณจะเห็น:** "disconnected (1008): pairing required" @@ -50,190 +50,190 @@ UI ควบคุมเป็นแอปหน้าเดียวขนา openclaw devices list ``` - + ```bash openclaw devices approve ``` -หากเบราว์เซอร์ลองจับคู่อีกครั้งโดยมีรายละเอียดการยืนยันตัวตนเปลี่ยนไป (บทบาท/ขอบเขต/กุญแจสาธารณะ) คำขอที่รอดำเนินการก่อนหน้าจะถูกแทนที่ และจะมีการสร้าง `requestId` ใหม่ ให้รัน `openclaw devices list` อีกครั้งก่อนอนุมัติ +หากเบราว์เซอร์ลองจับคู่อีกครั้งด้วยรายละเอียด Auth ที่เปลี่ยนไป (บทบาท/ขอบเขต/กุญแจสาธารณะ) คำขอที่รอดำเนินการก่อนหน้าจะถูกแทนที่ และจะมีการสร้าง `requestId` ใหม่ ให้รัน `openclaw devices list` อีกครั้งก่อนอนุมัติ -หากเบราว์เซอร์จับคู่แล้ว และคุณเปลี่ยนจากสิทธิ์อ่านเป็นสิทธิ์เขียน/ผู้ดูแลระบบ ระบบจะถือว่านี่เป็นการอัปเกรดการอนุมัติ ไม่ใช่การเชื่อมต่อใหม่แบบเงียบ ๆ OpenClaw จะคงการอนุมัติเดิมไว้ บล็อกการเชื่อมต่อใหม่ที่มีขอบเขตกว้างกว่า และขอให้คุณอนุมัติชุดขอบเขตใหม่อย่างชัดเจน +หากเบราว์เซอร์จับคู่ไว้แล้ว และคุณเปลี่ยนจากสิทธิ์อ่านเป็นสิทธิ์เขียน/ผู้ดูแลระบบ การเปลี่ยนนี้จะถือเป็นการอัปเกรดการอนุมัติ ไม่ใช่การเชื่อมต่อใหม่แบบเงียบ OpenClaw จะคงการอนุมัติเดิมไว้ บล็อกการเชื่อมต่อใหม่ที่มีสิทธิ์กว้างขึ้น และขอให้คุณอนุมัติชุดขอบเขตใหม่อย่างชัดเจน -เมื่ออนุมัติแล้ว อุปกรณ์จะถูกจดจำและจะไม่ต้องอนุมัติซ้ำ เว้นแต่คุณจะเพิกถอนด้วย `openclaw devices revoke --device --role ` ดู [CLI อุปกรณ์](/th/cli/devices) สำหรับการหมุนเวียน token และการเพิกถอน +เมื่ออนุมัติแล้ว อุปกรณ์จะถูกจดจำและไม่ต้องอนุมัติซ้ำ เว้นแต่คุณจะเพิกถอนด้วย `openclaw devices revoke --device --role ` ดู [CLI สำหรับอุปกรณ์](/th/cli/devices) สำหรับการหมุนเวียนโทเค็นและการเพิกถอน -- การเชื่อมต่อเบราว์เซอร์แบบ local loopback โดยตรง (`127.0.0.1` / `localhost`) จะได้รับการอนุมัติอัตโนมัติ -- Tailscale Serve สามารถข้ามรอบการจับคู่สำหรับเซสชันผู้ปฏิบัติงานของ UI ควบคุมได้เมื่อ `gateway.auth.allowTailscale: true`, ข้อมูลประจำตัว Tailscale ตรวจสอบผ่าน และเบราว์เซอร์แสดงข้อมูลประจำตัวของอุปกรณ์ -- การผูก Tailnet โดยตรง การเชื่อมต่อเบราว์เซอร์ผ่าน LAN และโปรไฟล์เบราว์เซอร์ที่ไม่มีข้อมูลประจำตัวอุปกรณ์ยังคงต้องได้รับการอนุมัติอย่างชัดเจน -- โปรไฟล์เบราว์เซอร์แต่ละรายการจะสร้าง ID อุปกรณ์ที่ไม่ซ้ำกัน ดังนั้นการเปลี่ยนเบราว์เซอร์หรือล้างข้อมูลเบราว์เซอร์จะต้องจับคู่ใหม่ +- การเชื่อมต่อเบราว์เซอร์ผ่าน local loopback โดยตรง (`127.0.0.1` / `localhost`) จะได้รับการอนุมัติโดยอัตโนมัติ +- Tailscale Serve สามารถข้ามรอบการจับคู่สำหรับเซสชันผู้ปฏิบัติงาน Control UI ได้เมื่อ `gateway.auth.allowTailscale: true`, ตรวจสอบตัวตน Tailscale สำเร็จ และเบราว์เซอร์แสดงตัวตนอุปกรณ์ของตน +- การ bind กับ Tailnet โดยตรง, การเชื่อมต่อเบราว์เซอร์ผ่าน LAN และโปรไฟล์เบราว์เซอร์ที่ไม่มีตัวตนอุปกรณ์ยังคงต้องได้รับการอนุมัติอย่างชัดเจน +- แต่ละโปรไฟล์เบราว์เซอร์จะสร้าง ID อุปกรณ์ที่ไม่ซ้ำกัน ดังนั้นการเปลี่ยนเบราว์เซอร์หรือล้างข้อมูลเบราว์เซอร์จะต้องจับคู่ใหม่ -## ข้อมูลประจำตัวส่วนบุคคล (ภายในเบราว์เซอร์) +## ตัวตนส่วนบุคคล (ภายในเบราว์เซอร์) -UI ควบคุมรองรับข้อมูลประจำตัวส่วนบุคคลต่อเบราว์เซอร์ (ชื่อที่แสดงและอวาตาร์) ซึ่งแนบกับข้อความขาออกเพื่อระบุผู้ส่งในเซสชันที่ใช้ร่วมกัน ข้อมูลนี้อยู่ในที่เก็บข้อมูลของเบราว์เซอร์ จำกัดขอบเขตอยู่ที่โปรไฟล์เบราว์เซอร์ปัจจุบัน และไม่ซิงค์ไปยังอุปกรณ์อื่นหรือคงอยู่ฝั่งเซิร์ฟเวอร์ นอกเหนือจากเมตาดาต้าผู้เขียน transcript ตามปกติบนข้อความที่คุณส่งจริง การล้างข้อมูลไซต์หรือเปลี่ยนเบราว์เซอร์จะรีเซ็ตข้อมูลนี้ให้ว่างเปล่า +Control UI รองรับตัวตนส่วนบุคคลต่อเบราว์เซอร์ (ชื่อที่แสดงและอวาตาร์) ที่แนบกับข้อความขาออกเพื่อการระบุแหล่งที่มาในเซสชันที่ใช้ร่วมกัน ตัวตนนี้อยู่ในที่เก็บข้อมูลของเบราว์เซอร์ ถูกจำกัดขอบเขตไว้ที่โปรไฟล์เบราว์เซอร์ปัจจุบัน และไม่ซิงค์ไปยังอุปกรณ์อื่นหรือจัดเก็บถาวรฝั่งเซิร์ฟเวอร์ นอกเหนือจากเมทาดาทาการเป็นผู้เขียนทรานสคริปต์ตามปกติบนข้อความที่คุณส่งจริง การล้างข้อมูลไซต์หรือเปลี่ยนเบราว์เซอร์จะรีเซ็ตให้ว่างเปล่า -รูปแบบภายในเบราว์เซอร์เดียวกันนี้ใช้กับการแทนที่อวาตาร์ของผู้ช่วยด้วย อวาตาร์ผู้ช่วยที่อัปโหลดจะซ้อนทับข้อมูลประจำตัวที่ Gateway แก้ไขได้เฉพาะบนเบราว์เซอร์ภายในเครื่องเท่านั้น และจะไม่เดินทางไปกลับผ่าน `config.patch` ฟิลด์ config ที่ใช้ร่วมกัน `ui.assistant.avatar` ยังคงพร้อมใช้งานสำหรับไคลเอนต์ที่ไม่ใช่ UI ซึ่งเขียนฟิลด์นี้โดยตรง (เช่น gateway แบบสคริปต์หรือแดชบอร์ดแบบกำหนดเอง) +รูปแบบภายในเบราว์เซอร์เดียวกันนี้ใช้กับการแทนที่อวาตาร์ผู้ช่วยด้วย อวาตาร์ผู้ช่วยที่อัปโหลดจะซ้อนทับตัวตนที่ Gateway ระบุได้เฉพาะบนเบราว์เซอร์ภายในเครื่อง และจะไม่ส่งไปกลับผ่าน `config.patch` ฟิลด์การตั้งค่า `ui.assistant.avatar` ที่ใช้ร่วมกันยังคงพร้อมใช้งานสำหรับไคลเอนต์ที่ไม่ใช่ UI ซึ่งเขียนฟิลด์นี้โดยตรง (เช่น Gateway แบบสคริปต์หรือแดชบอร์ดแบบกำหนดเอง) -## ปลายทาง config ขณะรันไทม์ +## เอนด์พอยต์การตั้งค่ารันไทม์ -UI ควบคุมดึงการตั้งค่าขณะรันไทม์จาก `/__openclaw/control-ui-config.json` ปลายทางนี้ถูกควบคุมด้วยการยืนยันตัวตน Gateway เดียวกับพื้นผิว HTTP ส่วนที่เหลือ: เบราว์เซอร์ที่ไม่ได้ยืนยันตัวตนจะดึงข้อมูลไม่ได้ และการดึงข้อมูลสำเร็จต้องมี gateway token/รหัสผ่านที่ถูกต้องอยู่แล้ว ข้อมูลประจำตัว Tailscale Serve หรือข้อมูลประจำตัวพร็อกซีที่เชื่อถือได้ +Control UI ดึงการตั้งค่ารันไทม์จาก `/__openclaw/control-ui-config.json` เอนด์พอยต์นั้นถูกควบคุมด้วย Auth ของ Gateway เดียวกันกับพื้นผิว HTTP ส่วนที่เหลือ: เบราว์เซอร์ที่ไม่ได้ยืนยันตัวตนจะดึงข้อมูลไม่ได้ และการดึงข้อมูลที่สำเร็จต้องมีโทเค็น/รหัสผ่าน Gateway ที่ยังใช้ได้อยู่แล้ว, ตัวตน Tailscale Serve หรือ ตัวตนพร็อกซีที่เชื่อถือได้ ## การรองรับภาษา -UI ควบคุมสามารถแปลตัวเองตาม locale ของเบราว์เซอร์ในการโหลดครั้งแรก หากต้องการแทนที่ภายหลัง ให้เปิด **ภาพรวม -> การเข้าถึง Gateway -> ภาษา** ตัวเลือก locale อยู่ในการ์ดการเข้าถึง Gateway ไม่ได้อยู่ใต้ลักษณะภายนอก +Control UI สามารถปรับภาษาให้ตรงกับโลเคลของเบราว์เซอร์ในการโหลดครั้งแรก หากต้องการแทนที่ในภายหลัง ให้เปิด **ภาพรวม -> การเข้าถึง Gateway -> ภาษา** ตัวเลือกโลเคลอยู่ในการ์ดการเข้าถึง Gateway ไม่ได้อยู่ใต้ลักษณะที่ปรากฏ -- locale ที่รองรับ: `en`, `zh-CN`, `zh-TW`, `pt-BR`, `de`, `es`, `ja-JP`, `ko`, `fr`, `ar`, `it`, `tr`, `uk`, `id`, `pl`, `th`, `vi`, `nl`, `fa` -- คำแปลที่ไม่ใช่ภาษาอังกฤษจะถูกโหลดแบบ lazy ในเบราว์เซอร์ -- locale ที่เลือกจะถูกบันทึกในที่เก็บข้อมูลของเบราว์เซอร์และนำกลับมาใช้ในการเข้าชมครั้งต่อไป -- คีย์คำแปลที่หายไปจะถอยกลับไปใช้ภาษาอังกฤษ +- โลเคลที่รองรับ: `en`, `zh-CN`, `zh-TW`, `pt-BR`, `de`, `es`, `ja-JP`, `ko`, `fr`, `ar`, `it`, `tr`, `uk`, `id`, `pl`, `th`, `vi`, `nl`, `fa` +- คำแปลที่ไม่ใช่ภาษาอังกฤษจะถูก lazy-load ในเบราว์เซอร์ +- โลเคลที่เลือกจะถูกบันทึกในที่เก็บข้อมูลของเบราว์เซอร์และนำกลับมาใช้ในการเข้าชมครั้งต่อไป +- คีย์คำแปลที่ขาดหายจะ fallback เป็นภาษาอังกฤษ -คำแปลเอกสารถูกสร้างสำหรับชุด locale ที่ไม่ใช่ภาษาอังกฤษเดียวกัน แต่ตัวเลือกภาษา Mintlify ในตัวของไซต์เอกสารจำกัดเฉพาะรหัส locale ที่ Mintlify ยอมรับ เอกสารภาษาไทย (`th`) และเปอร์เซีย (`fa`) ยังคงถูกสร้างใน publish repo แต่อาจยังไม่ปรากฏในตัวเลือกนั้นจนกว่า Mintlify จะรองรับรหัสเหล่านี้ +คำแปลเอกสารจะถูกสร้างสำหรับชุดโลเคลที่ไม่ใช่ภาษาอังกฤษเดียวกัน แต่ตัวเลือกภาษา Mintlify ในตัวของไซต์เอกสารถูกจำกัดไว้ที่รหัสโลเคลที่ Mintlify ยอมรับ เอกสารภาษาไทย (`th`) และเปอร์เซีย (`fa`) ยังคงถูกสร้างใน repo สำหรับเผยแพร่ แต่อาจยังไม่ปรากฏในตัวเลือกนั้นจนกว่า Mintlify จะรองรับรหัสเหล่านั้น -## ธีมลักษณะภายนอก +## ธีมลักษณะที่ปรากฏ -แผงลักษณะภายนอกเก็บธีมในตัว Claw, Knot และ Dash รวมถึงช่องนำเข้า tweakcn แบบภายในเบราว์เซอร์หนึ่งช่อง หากต้องการนำเข้าธีม ให้เปิด [ธีม tweakcn](https://tweakcn.com/themes), เลือกหรือสร้างธีม, คลิก **แชร์** แล้ววางลิงก์ธีมที่คัดลอกไว้ในลักษณะภายนอก ตัวนำเข้ายังรองรับ URL registry แบบ `https://tweakcn.com/r/themes/`, URL editor เช่น `https://tweakcn.com/editor/theme?theme=amethyst-haze`, พาธสัมพัทธ์ `/themes/`, ID ธีมดิบ และชื่อธีมเริ่มต้น เช่น `amethyst-haze` +แผงลักษณะที่ปรากฏยังคงมีธีม Claw, Knot และ Dash ในตัว รวมถึงช่องนำเข้า tweakcn แบบภายในเบราว์เซอร์หนึ่งช่อง หากต้องการนำเข้าธีม ให้เปิด [tweakcn editor](https://tweakcn.com/editor/theme), เลือกหรือสร้างธีม, คลิก **แชร์** และวางลิงก์ธีมที่คัดลอกไว้ลงในลักษณะที่ปรากฏ ตัวนำเข้ายังรองรับ URL รีจิสทรี `https://tweakcn.com/r/themes/`, URL ตัวแก้ไขอย่าง `https://tweakcn.com/editor/theme?theme=amethyst-haze`, พาธสัมพัทธ์ `/themes/`, ID ธีมดิบ และชื่อธีมเริ่มต้น เช่น `amethyst-haze` -ธีมที่นำเข้าจะถูกเก็บไว้เฉพาะในโปรไฟล์เบราว์เซอร์ปัจจุบันเท่านั้น ธีมเหล่านี้จะไม่ถูกเขียนลงใน config ของ Gateway และไม่ซิงค์ข้ามอุปกรณ์ การแทนที่ธีมที่นำเข้าจะอัปเดตช่องภายในหนึ่งช่องนั้น การล้างธีมจะเปลี่ยนธีมที่ใช้งานอยู่กลับเป็น Claw หากธีมที่นำเข้าถูกเลือกอยู่ +ธีมที่นำเข้าจะถูกเก็บไว้เฉพาะในโปรไฟล์เบราว์เซอร์ปัจจุบันเท่านั้น ธีมเหล่านี้จะไม่ถูกเขียนลงในการตั้งค่า Gateway และไม่ซิงค์ข้ามอุปกรณ์ การแทนที่ธีมที่นำเข้าจะอัปเดตช่องภายในเครื่องเพียงช่องเดียว การล้างธีมจะเปลี่ยนธีมที่ใช้งานกลับไปเป็น Claw หากธีมที่นำเข้าเคยถูกเลือกไว้ -## สิ่งที่ทำได้ (ปัจจุบัน) +## สิ่งที่ทำได้ (ตอนนี้) - แชทกับโมเดลผ่าน Gateway WS (`chat.history`, `chat.send`, `chat.abort`, `chat.inject`) - - พูดคุยผ่านเซสชันเรียลไทม์ของเบราว์เซอร์ OpenAI ใช้ WebRTC โดยตรง, Google Live ใช้ token เบราว์เซอร์แบบใช้ครั้งเดียวที่ถูกจำกัดผ่าน WebSocket และ plugin เสียงเรียลไทม์แบบ backend-only ใช้ทรานสปอร์ต relay ของ Gateway relay จะเก็บข้อมูลรับรองของผู้ให้บริการไว้บน Gateway ขณะที่เบราว์เซอร์สตรีม PCM จากไมโครโฟนผ่าน RPC `talk.realtime.relay*` และส่งการเรียกเครื่องมือ `openclaw_agent_consult` กลับผ่าน `chat.send` สำหรับโมเดล OpenClaw ขนาดใหญ่กว่าที่กำหนดค่าไว้ - - สตรีมการเรียกเครื่องมือ + การ์ดผลลัพธ์เครื่องมือสดในแชท (เหตุการณ์ agent) + - พูดคุยผ่านเซสชันเรียลไทม์ของเบราว์เซอร์ OpenAI ใช้ WebRTC โดยตรง, Google Live ใช้โทเค็นเบราว์เซอร์แบบใช้ครั้งเดียวที่มีข้อจำกัดผ่าน WebSocket และ Plugin เสียงเรียลไทม์เฉพาะแบ็กเอนด์ใช้ทรานสปอร์ต relay ของ Gateway relay จะเก็บข้อมูลรับรองของผู้ให้บริการไว้บน Gateway ขณะที่เบราว์เซอร์สตรีม PCM จากไมโครโฟนผ่าน RPC `talk.realtime.relay*` และส่งการเรียกเครื่องมือ `openclaw_agent_consult` กลับผ่าน `chat.send` สำหรับโมเดล OpenClaw ที่ตั้งค่าไว้ขนาดใหญ่กว่า + - สตรีมการเรียกเครื่องมือ + การ์ดเอาต์พุตเครื่องมือแบบสดในแชท (เหตุการณ์ของเอเจนต์) - - ช่องทาง: สถานะช่องทางในตัวรวมถึง plugin ที่ bundled/ภายนอก, การเข้าสู่ระบบ QR และ config รายช่องทาง (`channels.status`, `web.login.*`, `config.patch`) + - ช่องทาง: สถานะช่องทางในตัวและช่องทาง Plugin แบบ bundled/ภายนอก, การเข้าสู่ระบบด้วย QR และการตั้งค่าต่อช่องทาง (`channels.status`, `web.login.*`, `config.patch`) - อินสแตนซ์: รายการ presence + รีเฟรช (`system-presence`) - - เซสชัน: รายการ + การแทนที่โมเดล/thinking/fast/verbose/trace/reasoning รายเซสชัน (`sessions.list`, `sessions.patch`) - - ความฝัน: สถานะ dreaming, สวิตช์เปิด/ปิด และตัวอ่านบันทึกความฝัน (`doctor.memory.status`, `doctor.memory.dreamDiary`, `config.patch`) + - เซสชัน: รายการ + การแทนที่โมเดล/การคิด/เร็ว/ละเอียด/trace/reasoning ต่อเซสชัน (`sessions.list`, `sessions.patch`) + - ความฝัน: สถานะ Dreaming, สวิตช์เปิด/ปิด และตัวอ่านบันทึกความฝัน (`doctor.memory.status`, `doctor.memory.dreamDiary`, `config.patch`) - งาน Cron: แสดงรายการ/เพิ่ม/แก้ไข/รัน/เปิดใช้งาน/ปิดใช้งาน + ประวัติการรัน (`cron.*`) - Skills: สถานะ, เปิดใช้งาน/ปิดใช้งาน, ติดตั้ง, อัปเดต API key (`skills.*`) - - Node: รายการ + caps (`node.list`) - - การอนุมัติ exec: แก้ไข allowlist ของ gateway หรือ node + นโยบาย ask สำหรับ `exec host=gateway/node` (`exec.approvals.*`) + - Node: รายการ + ความสามารถ (`node.list`) + - การอนุมัติ exec: แก้ไข allowlist ของ Gateway หรือ Node + นโยบายถามสำหรับ `exec host=gateway/node` (`exec.approvals.*`) - + - ดู/แก้ไข `~/.openclaw/openclaw.json` (`config.get`, `config.set`) - - ใช้ค่า + รีสตาร์ทพร้อมการตรวจสอบความถูกต้อง (`config.apply`) และปลุกเซสชันที่ใช้งานล่าสุด - - การเขียนมี guard แบบ base-hash เพื่อป้องกันการทับการแก้ไขพร้อมกัน - - การเขียน (`config.set`/`config.apply`/`config.patch`) จะ preflight การแก้ SecretRef ที่ใช้งานอยู่สำหรับ ref ใน payload config ที่ส่งมา; ref ที่ส่งมาซึ่งใช้งานอยู่แต่แก้ไม่ได้จะถูกปฏิเสธก่อนเขียน - - การเรนเดอร์ schema + form (`config.schema` / `config.schema.lookup`, รวมถึงฟิลด์ `title` / `description`, hint ของ UI ที่ตรงกัน, สรุปลูกโดยตรง, เมตาดาต้าเอกสารบนโหนด object/wildcard/array/composition ที่ซ้อนกัน รวมถึง schema ของ plugin + ช่องทางเมื่อมี); editor Raw JSON พร้อมใช้งานเฉพาะเมื่อ snapshot มี raw round-trip ที่ปลอดภัย - - หาก snapshot ไม่สามารถ round-trip ข้อความ raw ได้อย่างปลอดภัย Control UI จะบังคับใช้โหมด Form และปิดใช้งานโหมด Raw สำหรับ snapshot นั้น - - editor Raw JSON "รีเซ็ตเป็นค่าที่บันทึกไว้" จะรักษารูปทรงที่เขียนแบบ raw (การจัดรูปแบบ, ความคิดเห็น, layout `$include`) แทนการเรนเดอร์ snapshot แบบแบนใหม่ ดังนั้นการแก้ไขภายนอกจะยังอยู่หลังรีเซ็ตเมื่อ snapshot สามารถ round-trip ได้อย่างปลอดภัย - - ค่า object SecretRef แบบมีโครงสร้างจะแสดงเป็นแบบอ่านอย่างเดียวใน input ข้อความของฟอร์ม เพื่อป้องกันการทำให้ object กลายเป็น string โดยไม่ตั้งใจ + - ใช้การตั้งค่า + รีสตาร์ทพร้อมการตรวจสอบ (`config.apply`) และปลุกเซสชันที่ใช้งานล่าสุด + - การเขียนมีตัวป้องกัน base-hash เพื่อป้องกันการเขียนทับการแก้ไขที่เกิดขึ้นพร้อมกัน + - การเขียน (`config.set`/`config.apply`/`config.patch`) จะตรวจสอบล่วงหน้าการ resolve SecretRef ที่ active สำหรับ refs ใน payload การตั้งค่าที่ส่งมา; refs ที่ active และส่งมาซึ่ง resolve ไม่ได้จะถูกปฏิเสธก่อนเขียน + - การเรนเดอร์สคีมา + ฟอร์ม (`config.schema` / `config.schema.lookup`, รวมถึงฟิลด์ `title` / `description`, UI hints ที่ตรงกัน, สรุปลูกโดยตรง, เมทาดาทาเอกสารบนโหนด object/wildcard/array/composition ที่ซ้อนกัน รวมถึงสคีมา Plugin + ช่องทางเมื่อพร้อมใช้งาน); ตัวแก้ไข Raw JSON จะพร้อมใช้งานเฉพาะเมื่อ snapshot มีการ round-trip แบบ raw ที่ปลอดภัย + - หาก snapshot ไม่สามารถ round-trip ข้อความ raw ได้อย่างปลอดภัย Control UI จะบังคับใช้โหมดฟอร์มและปิดใช้งานโหมด Raw สำหรับ snapshot นั้น + - "รีเซ็ตเป็นค่าที่บันทึกไว้" ของตัวแก้ไข Raw JSON จะรักษารูปร่างที่เขียนแบบ raw ไว้ (การจัดรูปแบบ, ความคิดเห็น, เลย์เอาต์ `$include`) แทนการเรนเดอร์ snapshot แบบแบนใหม่ ดังนั้นการแก้ไขภายนอกจะยังคงอยู่หลังการรีเซ็ตเมื่อ snapshot สามารถ round-trip ได้อย่างปลอดภัย + - ค่า object ของ SecretRef แบบมีโครงสร้างจะแสดงเป็นแบบอ่านอย่างเดียวในช่องข้อความของฟอร์ม เพื่อป้องกันการทำให้ object กลายเป็น string โดยไม่ตั้งใจ - ดีบัก: snapshot สถานะ/สุขภาพ/โมเดล + บันทึกเหตุการณ์ + การเรียก RPC ด้วยตนเอง (`status`, `health`, `models.list`) - - บันทึก: tail สดของไฟล์ log ของ gateway พร้อมตัวกรอง/ส่งออก (`logs.tail`) - - อัปเดต: รันการอัปเดต package/git + รีสตาร์ท (`update.run`) พร้อมรายงานการรีสตาร์ท จากนั้น poll `update.status` หลังเชื่อมต่อใหม่เพื่อตรวจสอบเวอร์ชัน gateway ที่กำลังทำงาน + - บันทึก: tail แบบสดของบันทึกไฟล์ Gateway พร้อมตัวกรอง/ส่งออก (`logs.tail`) + - อัปเดต: รันการอัปเดตแพ็กเกจ/git + รีสตาร์ท (`update.run`) พร้อมรายงานการรีสตาร์ท จากนั้น poll `update.status` หลังเชื่อมต่อใหม่เพื่อตรวจสอบเวอร์ชัน Gateway ที่กำลังทำงาน - - สำหรับงานแบบแยกเดี่ยว ค่า delivery เริ่มต้นคือการประกาศสรุป คุณสามารถเปลี่ยนเป็น none ได้หากต้องการการรันภายในเท่านั้น + - สำหรับงานที่แยกอิสระ ค่าเริ่มต้นของการส่งคือประกาศสรุป คุณสามารถเปลี่ยนเป็นไม่มีได้หากต้องการการรันเฉพาะภายใน - ฟิลด์ช่องทาง/เป้าหมายจะปรากฏเมื่อเลือกประกาศ - - โหมด Webhook ใช้ `delivery.mode = "webhook"` โดยตั้งค่า `delivery.to` เป็น URL HTTP(S) webhook ที่ถูกต้อง - - สำหรับงาน main-session จะมีโหมด delivery แบบ webhook และ none ให้ใช้ - - ตัวควบคุมการแก้ไขขั้นสูงรวมถึง delete-after-run, ล้าง agent override, ตัวเลือก cron exact/stagger, การแทนที่โมเดล/thinking ของ agent และสวิตช์ delivery แบบ best-effort - - การตรวจสอบความถูกต้องของฟอร์มอยู่ในบรรทัดเดียวกับข้อผิดพลาดระดับฟิลด์; ค่าที่ไม่ถูกต้องจะปิดใช้งานปุ่มบันทึกจนกว่าจะได้รับการแก้ไข - - ตั้งค่า `cron.webhookToken` เพื่อส่ง bearer token เฉพาะ หากละเว้น webhook จะถูกส่งโดยไม่มีส่วนหัว auth - - fallback ที่เลิกใช้แล้ว: งาน legacy ที่เก็บไว้พร้อม `notify: true` ยังสามารถใช้ `cron.webhook` ได้จนกว่าจะย้ายข้อมูล + - โหมด Webhook ใช้ `delivery.mode = "webhook"` พร้อมตั้งค่า `delivery.to` เป็น URL HTTP(S) webhook ที่ถูกต้อง + - สำหรับงาน main-session สามารถใช้โหมดการส่งแบบ Webhook และไม่มีได้ + - ตัวควบคุมการแก้ไขขั้นสูงประกอบด้วย delete-after-run, ล้างการแทนที่เอเจนต์, ตัวเลือก cron exact/stagger, การแทนที่โมเดล/การคิดของเอเจนต์ และสวิตช์การส่งแบบ best-effort + - การตรวจสอบฟอร์มเป็นแบบ inline พร้อมข้อผิดพลาดระดับฟิลด์; ค่าที่ไม่ถูกต้องจะปิดใช้งานปุ่มบันทึกจนกว่าจะแก้ไข + - ตั้งค่า `cron.webhookToken` เพื่อส่ง bearer token เฉพาะ หากละไว้ Webhook จะถูกส่งโดยไม่มีส่วนหัว Auth + - fallback ที่เลิกใช้แล้ว: งาน legacy ที่จัดเก็บไว้พร้อม `notify: true` ยังสามารถใช้ `cron.webhook` ได้จนกว่าจะย้ายข้อมูล -## พฤติกรรมการแชท +## พฤติกรรมแชท - - `chat.send` เป็นแบบ **ไม่บล็อก**: ตอบรับทันทีด้วย `{ runId, status: "started" }` และสตรีมคำตอบผ่านเหตุการณ์ `chat` - - การอัปโหลดในแชตรองรับรูปภาพและไฟล์ที่ไม่ใช่วิดีโอ รูปภาพจะคงพาธรูปภาพเดิม ส่วนไฟล์อื่นจะถูกจัดเก็บเป็นสื่อที่มีการจัดการและแสดงในประวัติเป็นลิงก์ไฟล์แนบ - - การส่งซ้ำด้วย `idempotencyKey` เดิมจะคืนค่า `{ status: "in_flight" }` ขณะกำลังทำงาน และ `{ status: "ok" }` หลังเสร็จสมบูรณ์ - - การตอบกลับของ `chat.history` มีการจำกัดขนาดเพื่อความปลอดภัยของ UI เมื่อรายการทรานสคริปต์มีขนาดใหญ่เกินไป Gateway อาจตัดทอนฟิลด์ข้อความยาว ๆ ละเว้นบล็อกเมทาดาทาหนัก ๆ และแทนที่ข้อความที่ใหญ่เกินด้วยตัวยึดตำแหน่ง (`[chat.history omitted: message too large]`) - - รูปภาพจากผู้ช่วยหรือที่สร้างขึ้นจะถูกเก็บถาวรเป็นการอ้างอิงสื่อที่มีการจัดการ และถูกส่งกลับผ่าน URL สื่อของ Gateway ที่ยืนยันตัวตนแล้ว ดังนั้นการโหลดซ้ำจึงไม่ขึ้นอยู่กับ payload รูปภาพ base64 ดิบที่ต้องคงอยู่ในการตอบกลับประวัติแชต - - `chat.history` ยังลบแท็กคำสั่งแบบอินไลน์ที่ใช้เพื่อการแสดงผลเท่านั้นออกจากข้อความผู้ช่วยที่มองเห็นได้ (เช่น `[[reply_to_*]]` และ `[[audio_as_voice]]`), payload XML ของการเรียกเครื่องมือแบบข้อความธรรมดา (รวมถึง `...`, `...`, `...`, `...` และบล็อกการเรียกเครื่องมือที่ถูกตัดทอน) และโทเค็นควบคุมโมเดลแบบ ASCII/เต็มความกว้างที่รั่วออกมา และละเว้นรายการผู้ช่วยที่ข้อความที่มองเห็นได้ทั้งหมดเป็นเพียงโทเค็นเงียบที่ตรงกันทุกตัวอักษร `NO_REPLY` / `no_reply` - - ระหว่างการส่งที่กำลังทำงานและการรีเฟรชประวัติขั้นสุดท้าย มุมมองแชตจะคงข้อความผู้ใช้/ผู้ช่วยแบบ optimistic ในเครื่องให้มองเห็นได้ หาก `chat.history` คืน snapshot ที่เก่ากว่าชั่วครู่ ทรานสคริปต์มาตรฐานจะแทนที่ข้อความในเครื่องเหล่านั้นเมื่อประวัติของ Gateway ตามทัน - - เหตุการณ์ `chat` แบบสดคือสถานะการส่งมอบ ขณะที่ `chat.history` ถูกสร้างใหม่จากทรานสคริปต์เซสชันถาวร หลังเหตุการณ์ tool-final Control UI จะโหลดประวัติใหม่และรวมเฉพาะส่วนท้ายแบบ optimistic ขนาดเล็ก ขอบเขตของทรานสคริปต์มีอธิบายไว้ใน [WebChat](/th/web/webchat) - - `chat.inject` เพิ่มบันทึกของผู้ช่วยต่อท้ายทรานสคริปต์เซสชันและกระจายเหตุการณ์ `chat` สำหรับการอัปเดตเฉพาะ UI (ไม่มีการรัน agent ไม่มีการส่งมอบผ่านช่องทาง) - - ตัวเลือกโมเดลและการคิดในส่วนหัวแชตจะแพตช์เซสชันที่ใช้งานอยู่ทันทีผ่าน `sessions.patch`; สิ่งเหล่านี้เป็นการ override เซสชันแบบถาวร ไม่ใช่ตัวเลือกการส่งสำหรับเทิร์นเดียวเท่านั้น - - การพิมพ์ `/new` ใน Control UI จะสร้างและสลับไปยังเซสชันแดชบอร์ดใหม่แบบเดียวกับ New Chat การพิมพ์ `/reset` จะคงการรีเซ็ตแบบในที่เดิมที่ชัดเจนของ Gateway สำหรับเซสชันปัจจุบัน - - ตัวเลือกโมเดลแชตจะขอมุมมองโมเดลที่กำหนดค่าไว้ของ Gateway หากมี `agents.defaults.models` allowlist นั้นจะขับเคลื่อนตัวเลือก มิฉะนั้นตัวเลือกจะแสดงรายการ `models.providers.*.models` ที่ระบุชัดเจนพร้อมผู้ให้บริการที่มีการยืนยันตัวตนที่ใช้งานได้ แค็ตตาล็อกเต็มยังคงพร้อมใช้งานผ่าน debug `models.list` RPC ด้วย `view: "all"` - - เมื่อรายงานการใช้งานเซสชัน Gateway สดแสดงแรงกดดันของบริบทสูง พื้นที่ตัวเรียบเรียงแชตจะแสดงประกาศบริบท และที่ระดับ Compaction ที่แนะนำ จะแสดงปุ่ม compact ที่รันเส้นทาง Compaction เซสชันปกติ snapshot โทเค็นที่ล้าสมัยจะถูกซ่อนไว้จนกว่า Gateway จะรายงานการใช้งานสดอีกครั้ง + - `chat.send` เป็นแบบ **ไม่บล็อก**: ตอบรับทันทีด้วย `{ runId, status: "started" }` และสตรีมการตอบกลับผ่านเหตุการณ์ `chat` + - การอัปโหลดแชตรองรับรูปภาพและไฟล์ที่ไม่ใช่วิดีโอ รูปภาพจะคงพาธรูปภาพดั้งเดิมไว้ ส่วนไฟล์อื่นจะถูกจัดเก็บเป็นสื่อที่จัดการโดยระบบและแสดงในประวัติเป็นลิงก์ไฟล์แนบ + - การส่งซ้ำด้วย `idempotencyKey` เดิมจะส่งคืน `{ status: "in_flight" }` ระหว่างที่กำลังทำงาน และ `{ status: "ok" }` หลังเสร็จสิ้น + - การตอบกลับของ `chat.history` ถูกจำกัดขนาดเพื่อความปลอดภัยของ UI เมื่อรายการทรานสคริปต์มีขนาดใหญ่เกินไป Gateway อาจตัดฟิลด์ข้อความยาว ละเว้นบล็อกเมทาดาทาที่หนัก และแทนที่ข้อความขนาดใหญ่เกินด้วยตัวยึดตำแหน่ง (`[chat.history omitted: message too large]`) + - รูปภาพจากผู้ช่วย/ที่สร้างขึ้นจะถูกคงไว้เป็นการอ้างอิงสื่อที่จัดการโดยระบบ และให้บริการกลับผ่าน URL สื่อของ Gateway ที่ผ่านการยืนยันตัวตน ดังนั้นการโหลดซ้ำจึงไม่ขึ้นอยู่กับเพย์โหลดรูปภาพ base64 ดิบที่ต้องคงอยู่ในการตอบกลับประวัติแชต + - `chat.history` ยังลบแท็กคำสั่งแบบอินไลน์ที่ใช้แสดงผลเท่านั้นออกจากข้อความผู้ช่วยที่มองเห็นได้ (เช่น `[[reply_to_*]]` และ `[[audio_as_voice]]`), เพย์โหลด XML การเรียกเครื่องมือแบบข้อความธรรมดา (รวมถึง `...`, `...`, `...`, `...` และบล็อกการเรียกเครื่องมือที่ถูกตัด), โทเค็นควบคุมโมเดล ASCII/เต็มความกว้างที่รั่วออกมา และละเว้นรายการผู้ช่วยที่ข้อความที่มองเห็นได้ทั้งหมดเป็นเพียงโทเค็นเงียบที่ตรงตัว `NO_REPLY` / `no_reply` + - ระหว่างการส่งที่ยังทำงานอยู่และการรีเฟรชประวัติครั้งสุดท้าย มุมมองแชตจะยังคงแสดงข้อความผู้ใช้/ผู้ช่วยแบบคาดการณ์ในเครื่องไว้ หาก `chat.history` ส่งคืนสแนปช็อตเก่าชั่วครู่ ทรานสคริปต์ที่เป็นแหล่งอ้างอิงจะแทนที่ข้อความในเครื่องเหล่านั้นเมื่อประวัติ Gateway ตามทัน + - เหตุการณ์ `chat` สดคือสถานะการส่งมอบ ขณะที่ `chat.history` ถูกสร้างใหม่จากทรานสคริปต์เซสชันที่คงทน หลังเหตุการณ์สุดท้ายของเครื่องมือ Control UI จะโหลดประวัติใหม่และผสานเฉพาะส่วนท้ายแบบคาดการณ์ขนาดเล็ก ขอบเขตของทรานสคริปต์มีเอกสารไว้ใน [WebChat](/th/web/webchat) + - `chat.inject` ผนวกบันทึกของผู้ช่วยเข้ากับทรานสคริปต์เซสชันและกระจายเหตุการณ์ `chat` สำหรับการอัปเดตเฉพาะ UI (ไม่มีการรันเอเจนต์ ไม่มีการส่งผ่านช่องทาง) + - ตัวเลือกโมเดลและการคิดในส่วนหัวแชตจะแพตช์เซสชันที่ใช้งานอยู่ทันทีผ่าน `sessions.patch`; สิ่งเหล่านี้เป็นการ override เซสชันแบบคงอยู่ ไม่ใช่ตัวเลือกการส่งที่ใช้เพียงหนึ่งรอบ + - การพิมพ์ `/new` ใน Control UI จะสร้างและสลับไปยังเซสชันแดชบอร์ดใหม่เดียวกับ New Chat การพิมพ์ `/reset` จะคงการรีเซ็ตในตำแหน่งแบบชัดเจนของ Gateway สำหรับเซสชันปัจจุบัน + - ตัวเลือกโมเดลแชตขอมุมมองโมเดลที่กำหนดค่าไว้ของ Gateway หากมี `agents.defaults.models` รายการอนุญาตนั้นจะขับเคลื่อนตัวเลือก มิฉะนั้นตัวเลือกจะแสดงรายการ `models.providers.*.models` ที่ระบุชัดเจน รวมถึงผู้ให้บริการที่มีการยืนยันตัวตนที่ใช้งานได้ แค็ตตาล็อกเต็มยังคงพร้อมใช้งานผ่าน RPC ดีบัก `models.list` พร้อม `view: "all"` + - เมื่อรายงานการใช้งานเซสชัน Gateway ใหม่แสดงแรงกดดันบริบทสูง พื้นที่ตัวแต่งข้อความแชตจะแสดงประกาศบริบท และที่ระดับ Compaction ที่แนะนำจะแสดงปุ่มย่อบริบทซึ่งเรียกใช้เส้นทาง Compaction เซสชันปกติ สแนปช็อตโทเค็นที่ล้าสมัยจะถูกซ่อนไว้จนกว่า Gateway จะรายงานการใช้งานใหม่อีกครั้ง - โหมดพูดคุยใช้ผู้ให้บริการเสียงเรียลไทม์ที่ลงทะเบียนไว้ กำหนดค่า OpenAI ด้วย `talk.provider: "openai"` พร้อม `talk.providers.openai.apiKey` หรือกำหนดค่า Google ด้วย `talk.provider: "google"` พร้อม `talk.providers.google.apiKey`; การกำหนดค่าผู้ให้บริการเรียลไทม์ของ Voice Call ยังสามารถนำกลับมาใช้เป็น fallback ได้ เบราว์เซอร์จะไม่ได้รับคีย์ API ผู้ให้บริการมาตรฐาน OpenAI จะได้รับ Realtime client secret แบบชั่วคราวสำหรับ WebRTC Google Live จะได้รับโทเค็นยืนยันตัวตน Live API แบบใช้ครั้งเดียวและจำกัดขอบเขตสำหรับเซสชัน WebSocket ของเบราว์เซอร์ โดยมีคำสั่งและการประกาศเครื่องมือที่ถูกล็อกไว้ในโทเค็นโดย Gateway ผู้ให้บริการที่เปิดเผยเฉพาะ backend realtime bridge จะทำงานผ่านการขนส่งแบบ relay ของ Gateway ดังนั้นข้อมูลรับรองและ vendor socket จะอยู่ฝั่งเซิร์ฟเวอร์ ขณะที่เสียงจากเบราว์เซอร์เคลื่อนผ่าน RPC ของ Gateway ที่ยืนยันตัวตนแล้ว พรอมป์เซสชัน Realtime ถูกประกอบโดย Gateway; `talk.realtime.session` ไม่ยอมรับการ override คำสั่งจากผู้เรียก + โหมดพูดคุยใช้ผู้ให้บริการเสียงเรียลไทม์ที่ลงทะเบียนไว้ กำหนดค่า OpenAI ด้วย `talk.provider: "openai"` พร้อม `talk.providers.openai.apiKey` หรือกำหนดค่า Google ด้วย `talk.provider: "google"` พร้อม `talk.providers.google.apiKey`; การกำหนดค่าผู้ให้บริการเรียลไทม์ของ Voice Call ยังสามารถนำกลับมาใช้เป็นทางสำรองได้ เบราว์เซอร์จะไม่ได้รับคีย์ API ผู้ให้บริการมาตรฐาน OpenAI จะได้รับ client secret ของ Realtime แบบชั่วคราวสำหรับ WebRTC Google Live จะได้รับโทเค็นยืนยันตัวตน Live API แบบใช้ครั้งเดียวที่จำกัดไว้สำหรับเซสชัน WebSocket ในเบราว์เซอร์ โดยมีคำสั่งและการประกาศเครื่องมือถูกล็อกไว้ในโทเค็นโดย Gateway ผู้ให้บริการที่เปิดเผยเฉพาะบริดจ์เรียลไทม์ฝั่งแบ็กเอนด์จะทำงานผ่านทรานสปอร์ตรีเลย์ของ Gateway ดังนั้นข้อมูลรับรองและซ็อกเก็ตของผู้ขายจะอยู่ฝั่งเซิร์ฟเวอร์ ขณะที่เสียงของเบราว์เซอร์เคลื่อนผ่าน RPC ของ Gateway ที่ผ่านการยืนยันตัวตน พรอมป์เซสชัน Realtime ถูกประกอบโดย Gateway; `talk.realtime.session` ไม่รับการ override คำสั่งที่ผู้เรียกส่งมา - ในตัวเรียบเรียง Chat ตัวควบคุม Talk คือปุ่มรูปคลื่นถัดจากปุ่มถอดเสียงด้วยไมโครโฟน เมื่อ Talk เริ่มต้น แถวสถานะของตัวเรียบเรียงจะแสดง `Connecting Talk...` จากนั้นแสดง `Talk live` ขณะเชื่อมต่อเสียงแล้ว หรือ `Asking OpenClaw...` ขณะการเรียกเครื่องมือเรียลไทม์กำลังปรึกษาโมเดลขนาดใหญ่กว่าที่กำหนดค่าไว้ผ่าน `chat.send` + ในตัวแต่งข้อความแชต ตัวควบคุม Talk คือปุ่มรูปคลื่นถัดจากปุ่มป้อนตามคำบอกด้วยไมโครโฟน เมื่อ Talk เริ่มต้น แถวสถานะของตัวแต่งข้อความจะแสดง `Connecting Talk...` จากนั้น `Talk live` ขณะเชื่อมต่อเสียงอยู่ หรือ `Asking OpenClaw...` ขณะที่การเรียกเครื่องมือเรียลไทม์กำลังปรึกษาโมเดลขนาดใหญ่ที่กำหนดค่าไว้ผ่าน `chat.send` - การ smoke แบบสดสำหรับ maintainer: `OPENAI_API_KEY=... GEMINI_API_KEY=... node --import tsx scripts/dev/realtime-talk-live-smoke.ts` ตรวจสอบการแลกเปลี่ยน SDP ของ OpenAI browser WebRTC, การตั้งค่า WebSocket ของเบราว์เซอร์สำหรับ Google Live constrained-token และ adapter เบราว์เซอร์ของ Gateway relay พร้อมสื่อไมโครโฟนจำลอง คำสั่งนี้พิมพ์เฉพาะสถานะผู้ให้บริการและไม่บันทึก secret + การทดสอบสดสำหรับผู้ดูแล: `OPENAI_API_KEY=... GEMINI_API_KEY=... node --import tsx scripts/dev/realtime-talk-live-smoke.ts` ตรวจสอบการแลกเปลี่ยน SDP ของ OpenAI browser WebRTC, การตั้งค่า WebSocket ในเบราว์เซอร์ของ Google Live constrained-token และอะแดปเตอร์เบราว์เซอร์รีเลย์ของ Gateway พร้อมสื่อไมโครโฟนจำลอง คำสั่งนี้พิมพ์เฉพาะสถานะผู้ให้บริการและไม่บันทึกความลับ - - คลิก **หยุด** (เรียก `chat.abort`) - - ขณะที่การรันกำลังทำงาน follow-up ปกติจะเข้าคิว คลิก **Steer** บนข้อความที่เข้าคิวเพื่อฉีด follow-up นั้นเข้าไปในเทิร์นที่กำลังทำงาน - - พิมพ์ `/stop` (หรือวลี abort แบบ standalone เช่น `stop`, `stop action`, `stop run`, `stop openclaw`, `please stop`) เพื่อ abort นอกแบนด์ - - `chat.abort` รองรับ `{ sessionKey }` (ไม่มี `runId`) เพื่อ abort การรันที่ทำงานอยู่ทั้งหมดสำหรับเซสชันนั้น + - คลิก **Stop** (เรียก `chat.abort`) + - ขณะที่การรันกำลังทำงาน การติดตามผลตามปกติจะเข้าคิว คลิก **Steer** บนข้อความที่อยู่ในคิวเพื่อฉีดการติดตามผลนั้นเข้าไปในรอบที่กำลังรัน + - พิมพ์ `/stop` (หรือวลีสั่งยกเลิกเดี่ยว ๆ เช่น `stop`, `stop action`, `stop run`, `stop openclaw`, `please stop`) เพื่อยกเลิกนอกแบนด์ + - `chat.abort` รองรับ `{ sessionKey }` (ไม่มี `runId`) เพื่อยกเลิกการรันที่ใช้งานอยู่ทั้งหมดสำหรับเซสชันนั้น - - - เมื่อการรันถูก abort ข้อความผู้ช่วยบางส่วนยังสามารถแสดงใน UI ได้ - - Gateway จะเก็บข้อความผู้ช่วยบางส่วนที่ถูก abort ไว้ในประวัติทรานสคริปต์เมื่อมีเอาต์พุตในบัฟเฟอร์ - - รายการที่เก็บไว้มีเมทาดาทา abort เพื่อให้ผู้บริโภคทรานสคริปต์แยกส่วนบางส่วนจาก abort ออกจากเอาต์พุตที่เสร็จสมบูรณ์ตามปกติได้ + + - เมื่อการรันถูกยกเลิก ข้อความผู้ช่วยบางส่วนยังสามารถแสดงใน UI ได้ + - Gateway คงข้อความผู้ช่วยบางส่วนที่ถูกยกเลิกไว้ในประวัติทรานสคริปต์เมื่อมีเอาต์พุตที่บัฟเฟอร์ไว้ + - รายการที่คงไว้มีเมทาดาทาการยกเลิก เพื่อให้ผู้บริโภคทรานสคริปต์แยกส่วนบางส่วนจากการยกเลิกออกจากเอาต์พุตที่เสร็จสมบูรณ์ตามปกติได้ ## การติดตั้ง PWA และ web push -Control UI มาพร้อม `manifest.webmanifest` และ service worker ดังนั้นเบราว์เซอร์สมัยใหม่จึงสามารถติดตั้งเป็น PWA แบบ standalone ได้ Web Push ช่วยให้ Gateway ปลุก PWA ที่ติดตั้งไว้ด้วยการแจ้งเตือนได้แม้แท็บหรือหน้าต่างเบราว์เซอร์จะไม่ได้เปิดอยู่ +Control UI มาพร้อม `manifest.webmanifest` และ service worker ดังนั้นเบราว์เซอร์สมัยใหม่จึงสามารถติดตั้งเป็น PWA แบบสแตนด์อโลนได้ Web Push ทำให้ Gateway ปลุก PWA ที่ติดตั้งแล้วด้วยการแจ้งเตือนได้ แม้เมื่อแท็บหรือหน้าต่างเบราว์เซอร์ไม่ได้เปิดอยู่ -| พื้นที่ใช้งาน | ทำหน้าที่อะไร | +| พื้นผิว | สิ่งที่ทำ | | ----------------------------------------------------- | ------------------------------------------------------------------ | -| `ui/public/manifest.webmanifest` | manifest ของ PWA เบราว์เซอร์จะแสดงตัวเลือก "ติดตั้งแอป" เมื่อเข้าถึงได้ | -| `ui/public/sw.js` | service worker ที่จัดการเหตุการณ์ `push` และการคลิกการแจ้งเตือน | -| `push/vapid-keys.json` (ใต้ไดเรกทอรีสถานะของ OpenClaw) | keypair ของ VAPID ที่สร้างอัตโนมัติ ใช้ลงนาม payload ของ Web Push | -| `push/web-push-subscriptions.json` | endpoint การสมัครรับข้อมูลของเบราว์เซอร์ที่เก็บถาวรไว้ | +| `ui/public/manifest.webmanifest` | Manifest ของ PWA เบราว์เซอร์จะเสนอ "ติดตั้งแอป" เมื่อเข้าถึงได้ | +| `ui/public/sw.js` | Service worker ที่จัดการเหตุการณ์ `push` และการคลิกการแจ้งเตือน | +| `push/vapid-keys.json` (ภายใต้ไดเรกทอรีสถานะ OpenClaw) | คู่คีย์ VAPID ที่สร้างอัตโนมัติ ใช้ลงนามเพย์โหลด Web Push | +| `push/web-push-subscriptions.json` | เอนด์พอยต์การสมัครรับของเบราว์เซอร์ที่คงไว้ | -Override keypair ของ VAPID ผ่าน env var บนกระบวนการ Gateway เมื่อคุณต้องการ pin คีย์ (สำหรับการปรับใช้หลายโฮสต์ การหมุนเวียน secret หรือการทดสอบ): +Override คู่คีย์ VAPID ผ่านตัวแปรสภาพแวดล้อมบนโปรเซส Gateway เมื่อคุณต้องการตรึงคีย์ (สำหรับการปรับใช้หลายโฮสต์ การหมุนเวียนความลับ หรือการทดสอบ): - `OPENCLAW_VAPID_PUBLIC_KEY` - `OPENCLAW_VAPID_PRIVATE_KEY` - `OPENCLAW_VAPID_SUBJECT` (ค่าเริ่มต้นคือ `mailto:openclaw@localhost`) -Control UI ใช้เมธอด Gateway ที่จำกัดด้วย scope เหล่านี้เพื่อลงทะเบียนและทดสอบการสมัครรับข้อมูลของเบราว์เซอร์: +Control UI ใช้เมธอด Gateway ที่จำกัดด้วยสโคปเหล่านี้เพื่อลงทะเบียนและทดสอบการสมัครรับของเบราว์เซอร์: - `push.web.vapidPublicKey` — ดึงคีย์สาธารณะ VAPID ที่ใช้งานอยู่ - `push.web.subscribe` — ลงทะเบียน `endpoint` พร้อม `keys.p256dh`/`keys.auth` -- `push.web.unsubscribe` — ลบ endpoint ที่ลงทะเบียนไว้ -- `push.web.test` — ส่งการแจ้งเตือนทดสอบไปยังการสมัครรับข้อมูลของผู้เรียก +- `push.web.unsubscribe` — ลบเอนด์พอยต์ที่ลงทะเบียนไว้ +- `push.web.test` — ส่งการแจ้งเตือนทดสอบไปยังการสมัครรับของผู้เรียก -Web Push เป็นอิสระจากเส้นทาง relay ของ iOS APNS (ดู [การกำหนดค่า](/th/gateway/configuration) สำหรับ push ที่มี relay รองรับ) และเมธอด `push.test` ที่มีอยู่ ซึ่งมุ่งเป้าไปที่การจับคู่มือถือแบบ native +Web Push เป็นอิสระจากเส้นทางรีเลย์ APNS ของ iOS (ดู [การกำหนดค่า](/th/gateway/configuration) สำหรับ push ที่มีรีเลย์รองรับ) และเมธอด `push.test` ที่มีอยู่ ซึ่งมุ่งเป้าไปที่การจับคู่มือถือแบบเนทีฟ -## การฝังแบบ hosted +## การฝังแบบโฮสต์ -ข้อความผู้ช่วยสามารถเรนเดอร์เนื้อหาเว็บแบบ hosted แบบอินไลน์ด้วย shortcode `[embed ...]` นโยบาย sandbox ของ iframe ถูกควบคุมโดย `gateway.controlUi.embedSandbox`: +ข้อความผู้ช่วยสามารถเรนเดอร์เนื้อหาเว็บที่โฮสต์ไว้แบบอินไลน์ด้วยชอร์ตโค้ด `[embed ...]` นโยบาย sandbox ของ iframe ถูกควบคุมโดย `gateway.controlUi.embedSandbox`: - ปิดการทำงานของสคริปต์ภายในการฝังแบบ hosted + ปิดใช้งานการรันสคริปต์ภายในการฝังที่โฮสต์ไว้ - - อนุญาตการฝังแบบโต้ตอบได้ขณะยังคงแยก origin ไว้ นี่คือค่าเริ่มต้นและมักเพียงพอสำหรับเกม/วิดเจ็ตเบราว์เซอร์แบบ self-contained + + อนุญาตการฝังแบบโต้ตอบได้ ขณะยังคงแยกต้นทางไว้ นี่คือค่าเริ่มต้นและโดยทั่วไปเพียงพอสำหรับเกม/วิดเจ็ตในเบราว์เซอร์แบบสแตนด์อโลน - - เพิ่ม `allow-same-origin` บน `allow-scripts` สำหรับเอกสาร same-site ที่ตั้งใจต้องใช้สิทธิ์ที่แข็งแรงกว่า + + เพิ่ม `allow-same-origin` บน `allow-scripts` สำหรับเอกสารในไซต์เดียวกันที่ตั้งใจต้องการสิทธิ์ที่แรงกว่า @@ -250,14 +250,14 @@ Web Push เป็นอิสระจากเส้นทาง relay ขอ ``` -ใช้ `trusted` เฉพาะเมื่อเอกสารที่ฝังต้องการพฤติกรรม same-origin จริง ๆ สำหรับเกมและแคนวาสโต้ตอบส่วนใหญ่ที่ agent สร้างขึ้น `scripts` เป็นตัวเลือกที่ปลอดภัยกว่า +ใช้ `trusted` เฉพาะเมื่อเอกสารที่ฝังจำเป็นต้องมีพฤติกรรม same-origin จริง ๆ สำหรับเกมและแคนวาสโต้ตอบส่วนใหญ่ที่เอเจนต์สร้างขึ้น `scripts` เป็นตัวเลือกที่ปลอดภัยกว่า -URL ฝัง `http(s)` ภายนอกแบบ absolute ยังคงถูกบล็อกโดยค่าเริ่มต้น หากคุณตั้งใจต้องการให้ `[embed url="https://..."]` โหลดหน้าของบุคคลที่สาม ให้ตั้งค่า `gateway.controlUi.allowExternalEmbedUrls: true` +URL การฝัง `http(s)` ภายนอกแบบสัมบูรณ์ยังคงถูกบล็อกโดยค่าเริ่มต้น หากคุณตั้งใจต้องการให้ `[embed url="https://..."]` โหลดหน้าของบุคคลที่สาม ให้ตั้งค่า `gateway.controlUi.allowExternalEmbedUrls: true` -## ความกว้างของข้อความแชต +## ความกว้างข้อความแชต -ข้อความแชตที่จัดกลุ่มใช้ max-width เริ่มต้นที่อ่านง่าย การปรับใช้บนจอกว้างสามารถ override ได้โดยไม่ต้องแพตช์ CSS ที่ bundled ไว้ ด้วยการตั้งค่า `gateway.controlUi.chatMessageMaxWidth`: +ข้อความแชตที่จัดกลุ่มใช้ค่า max-width เริ่มต้นที่อ่านง่าย การปรับใช้บนจอกว้างสามารถ override ได้โดยไม่ต้องแพตช์ CSS ที่รวมมา โดยตั้งค่า `gateway.controlUi.chatMessageMaxWidth`: ```json5 { @@ -269,13 +269,13 @@ URL ฝัง `http(s)` ภายนอกแบบ absolute ยังคงถ } ``` -ค่าจะถูกตรวจสอบก่อนถึงเบราว์เซอร์ ค่าที่รองรับรวมถึงความยาวและเปอร์เซ็นต์แบบธรรมดา เช่น `960px` หรือ `82%` พร้อมนิพจน์ความกว้างแบบจำกัด `min(...)`, `max(...)`, `clamp(...)`, `calc(...)` และ `fit-content(...)` +ค่าจะถูกตรวจสอบก่อนถึงเบราว์เซอร์ ค่าที่รองรับรวมถึงความยาวธรรมดาและเปอร์เซ็นต์ เช่น `960px` หรือ `82%` รวมทั้งนิพจน์ความกว้าง `min(...)`, `max(...)`, `clamp(...)`, `calc(...)` และ `fit-content(...)` แบบมีข้อจำกัด ## การเข้าถึง tailnet (แนะนำ) - - คง Gateway ไว้บน loopback และให้ Tailscale Serve ทำ proxy ด้วย HTTPS: + + ให้ Gateway อยู่บน loopback และให้ Tailscale Serve เป็นพร็อกซีด้วย HTTPS: ```bash openclaw gateway --tailscale serve @@ -285,16 +285,16 @@ URL ฝัง `http(s)` ภายนอกแบบ absolute ยังคงถ - `https:///` (หรือ `gateway.controlUi.basePath` ที่คุณกำหนดค่าไว้) - โดยค่าเริ่มต้น คำขอ Control UI/WebSocket Serve สามารถยืนยันตัวตนผ่าน header ตัวตนของ Tailscale (`tailscale-user-login`) เมื่อ `gateway.auth.allowTailscale` เป็น `true` OpenClaw ตรวจสอบตัวตนโดย resolve ที่อยู่ `x-forwarded-for` ด้วย `tailscale whois` และจับคู่กับ header และยอมรับเฉพาะเมื่อคำขอเข้าถึง loopback พร้อม header `x-forwarded-*` ของ Tailscale สำหรับเซสชันผู้ปฏิบัติงาน Control UI ที่มีตัวตนอุปกรณ์เบราว์เซอร์ เส้นทาง Serve ที่ตรวจสอบแล้วนี้ยังข้ามรอบการจับคู่อุปกรณ์ด้วย เบราว์เซอร์ที่ไม่มีอุปกรณ์และการเชื่อมต่อบทบาท node ยังคงทำตามการตรวจสอบอุปกรณ์ปกติ ตั้งค่า `gateway.auth.allowTailscale: false` หากคุณต้องการบังคับใช้ข้อมูลรับรอง shared-secret อย่างชัดเจนแม้กับทราฟฟิก Serve จากนั้นใช้ `gateway.auth.mode: "token"` หรือ `"password"` + โดยค่าเริ่มต้น คำขอ Control UI/WebSocket Serve สามารถยืนยันตัวตนผ่านส่วนหัวตัวตน Tailscale (`tailscale-user-login`) เมื่อ `gateway.auth.allowTailscale` เป็น `true` OpenClaw ตรวจสอบตัวตนโดย resolve ที่อยู่ `x-forwarded-for` ด้วย `tailscale whois` และจับคู่กับส่วนหัว และยอมรับเฉพาะเมื่อคำขอเข้ามาที่ loopback พร้อมส่วนหัว `x-forwarded-*` ของ Tailscale สำหรับเซสชันผู้ปฏิบัติงาน Control UI ที่มีตัวตนอุปกรณ์ของเบราว์เซอร์ เส้นทาง Serve ที่ผ่านการตรวจสอบนี้ยังข้ามรอบการจับคู่อุปกรณ์ด้วย เบราว์เซอร์ที่ไม่มีอุปกรณ์และการเชื่อมต่อบทบาท node ยังคงทำตามการตรวจสอบอุปกรณ์ตามปกติ ตั้งค่า `gateway.auth.allowTailscale: false` หากคุณต้องการบังคับใช้ข้อมูลรับรอง shared-secret อย่างชัดเจนแม้สำหรับทราฟฟิก Serve จากนั้นใช้ `gateway.auth.mode: "token"` หรือ `"password"` - สำหรับเส้นทางตัวตน Serve แบบ async นั้น ความพยายามยืนยันตัวตนที่ล้มเหลวสำหรับ IP ไคลเอนต์และ scope การยืนยันตัวตนเดียวกันจะถูกทำให้เป็นลำดับก่อนการเขียน rate-limit ดังนั้นการลองผิดซ้ำพร้อมกันจากเบราว์เซอร์เดียวกันอาจแสดง `retry later` ในคำขอที่สองแทนที่จะเป็น mismatch แบบธรรมดาสองรายการที่แข่งกันแบบขนาน + สำหรับเส้นทางตัวตน Serve แบบ async นั้น ความพยายามยืนยันตัวตนที่ล้มเหลวสำหรับ IP ไคลเอนต์และสโคปการยืนยันตัวตนเดียวกันจะถูกทำให้เป็นลำดับก่อนเขียน rate-limit ดังนั้นการลองผิดพร้อมกันจากเบราว์เซอร์เดียวกันอาจแสดง `retry later` ในคำขอที่สอง แทนที่จะเป็น mismatch ธรรมดาสองรายการที่แข่งกันแบบขนาน - การยืนยันตัวตน Serve แบบไม่มีโทเค็นถือว่าโฮสต์ gateway เชื่อถือได้ หากโค้ด local ที่ไม่น่าเชื่อถืออาจรันบนโฮสต์นั้น ให้บังคับใช้การยืนยันตัวตน token/password + การยืนยันตัวตน Serve แบบไม่มีโทเค็นถือว่าโฮสต์ gateway นั้นเชื่อถือได้ หากโค้ดในเครื่องที่ไม่เชื่อถืออาจรันบนโฮสต์นั้น ให้บังคับใช้การยืนยันตัวตนด้วย token/password - + ```bash openclaw gateway --bind tailnet --token "$(openssl rand -hex 32)" ``` @@ -312,19 +312,19 @@ URL ฝัง `http(s)` ภายนอกแบบ absolute ยังคงถ หากคุณเปิดแดชบอร์ดผ่าน HTTP ธรรมดา (`http://` หรือ `http://`) เบราว์เซอร์จะทำงานใน **บริบทที่ไม่ปลอดภัย** และบล็อก WebCrypto โดยค่าเริ่มต้น OpenClaw **บล็อก** การเชื่อมต่อ Control UI ที่ไม่มีตัวตนอุปกรณ์ -ข้อยกเว้นที่บันทึกไว้: +ข้อยกเว้นที่มีเอกสาร: -- ความเข้ากันได้กับ HTTP ที่ไม่ปลอดภัยเฉพาะ localhost ด้วย `gateway.controlUi.allowInsecureAuth=true` -- การยืนยันตัวตน Control UI ของผู้ปฏิบัติงานสำเร็จผ่าน `gateway.auth.mode: "trusted-proxy"` +- ความเข้ากันได้ของ HTTP ที่ไม่ปลอดภัยเฉพาะ localhost ด้วย `gateway.controlUi.allowInsecureAuth=true` +- การยืนยันตัวตน Control UI ของผู้ปฏิบัติงานที่สำเร็จผ่าน `gateway.auth.mode: "trusted-proxy"` - break-glass `gateway.controlUi.dangerouslyDisableDeviceAuth=true` -**การแก้ไขที่แนะนำ:** ใช้ HTTPS (Tailscale Serve) หรือเปิด UI ในเครื่อง: +**วิธีแก้ที่แนะนำ:** ใช้ HTTPS (Tailscale Serve) หรือเปิด UI ภายในเครื่อง: - `https:///` (Serve) - `http://127.0.0.1:18789/` (บนโฮสต์ Gateway) - + ```json5 { gateway: { @@ -335,14 +335,14 @@ URL ฝัง `http(s)` ภายนอกแบบ absolute ยังคงถ } ``` - `allowInsecureAuth` เป็นเพียงตัวสลับความเข้ากันได้สำหรับเครื่องภายในเท่านั้น: + `allowInsecureAuth` เป็นเพียงตัวสลับความเข้ากันได้ภายในเครื่องเท่านั้น: - - อนุญาตให้เซสชัน Control UI บน localhost ดำเนินต่อได้โดยไม่มีข้อมูลประจำตัวของอุปกรณ์ในบริบท HTTP ที่ไม่ปลอดภัย + - อนุญาตให้เซสชัน UI ควบคุมบน localhost ดำเนินต่อได้โดยไม่มีข้อมูลประจำตัวของอุปกรณ์ในบริบท HTTP ที่ไม่ปลอดภัย - ไม่ข้ามการตรวจสอบการจับคู่ - ไม่ผ่อนปรนข้อกำหนดข้อมูลประจำตัวของอุปกรณ์ระยะไกล (ที่ไม่ใช่ localhost) - + ```json5 { gateway: { @@ -354,14 +354,14 @@ URL ฝัง `http(s)` ภายนอกแบบ absolute ยังคงถ ``` - `dangerouslyDisableDeviceAuth` ปิดการตรวจสอบข้อมูลประจำตัวของอุปกรณ์สำหรับ Control UI และเป็นการลดระดับความปลอดภัยอย่างรุนแรง ให้ย้อนกลับโดยเร็วหลังใช้งานฉุกเฉิน + `dangerouslyDisableDeviceAuth` ปิดใช้งานการตรวจสอบข้อมูลประจำตัวของอุปกรณ์สำหรับ UI ควบคุม และเป็นการลดระดับความปลอดภัยอย่างรุนแรง ให้ย้อนกลับโดยเร็วหลังใช้ในเหตุฉุกเฉิน - - การรับรองความถูกต้องผ่านพร็อกซีที่เชื่อถือได้สำเร็จสามารถอนุญาตให้เซสชัน Control UI ของ **ผู้ปฏิบัติงาน** เข้าใช้งานได้โดยไม่มีข้อมูลประจำตัวของอุปกรณ์ - - สิ่งนี้ **ไม่** ขยายไปถึงเซสชัน Control UI บทบาท node - - พร็อกซีย้อนกลับแบบ loopback บนโฮสต์เดียวกันยังคงไม่ตรงตามการรับรองความถูกต้องของพร็อกซีที่เชื่อถือได้ ดู [การรับรองความถูกต้องด้วยพร็อกซีที่เชื่อถือได้](/th/gateway/trusted-proxy-auth) + - การยืนยันตัวตนผ่านพร็อกซีที่เชื่อถือได้สำเร็จสามารถอนุญาตเซสชัน UI ควบคุมของ **ผู้ปฏิบัติการ** ได้โดยไม่มีข้อมูลประจำตัวของอุปกรณ์ + - สิ่งนี้ **ไม่** ขยายไปถึงเซสชัน UI ควบคุมในบทบาทโหนด + - พร็อกซีแบบย้อนกลับ local loopback บนโฮสต์เดียวกันยังคงไม่ผ่านการยืนยันตัวตนแบบพร็อกซีที่เชื่อถือได้ ดู [การยืนยันตัวตนด้วยพร็อกซีที่เชื่อถือได้](/th/gateway/trusted-proxy-auth) @@ -370,36 +370,46 @@ URL ฝัง `http(s)` ภายนอกแบบ absolute ยังคงถ ## นโยบายความปลอดภัยของเนื้อหา -Control UI มาพร้อมนโยบาย `img-src` ที่เข้มงวด: อนุญาตเฉพาะแอสเซ็ตจาก **origin เดียวกัน**, URL `data:` และ URL `blob:` ที่สร้างในเครื่องเท่านั้น URL รูปภาพระยะไกลแบบ `http(s)` และแบบสัมพันธ์กับโปรโตคอลจะถูกเบราว์เซอร์ปฏิเสธและจะไม่ส่งคำขอดึงข้อมูลผ่านเครือข่าย +UI ควบคุมมาพร้อมกับนโยบาย `img-src` ที่เข้มงวด: อนุญาตเฉพาะแอสเซ็ต **ต้นทางเดียวกัน**, URL `data:`, และ URL `blob:` ที่สร้างภายในเครื่องเท่านั้น URL รูปภาพ `http(s)` ระยะไกลและ URL รูปภาพแบบสัมพันธ์กับโปรโตคอลจะถูกเบราว์เซอร์ปฏิเสธและจะไม่เกิดการดึงข้อมูลผ่านเครือข่าย -ความหมายในทางปฏิบัติ: +ในทางปฏิบัติ หมายความว่า: -- อวาตาร์และรูปภาพที่ให้บริการภายใต้พาธสัมพัทธ์ (เช่น `/avatars/`) ยังคงแสดงผล รวมถึง route อวาตาร์ที่ต้องรับรองความถูกต้องซึ่ง UI ดึงข้อมูลและแปลงเป็น URL `blob:` ภายในเครื่อง -- URL `data:image/...` แบบอินไลน์ยังคงแสดงผล (มีประโยชน์สำหรับ payload ภายในโปรโตคอล) -- URL `blob:` ภายในเครื่องที่สร้างโดย Control UI ยังคงแสดงผล -- URL อวาตาร์ระยะไกลที่ปล่อยออกมาจาก metadata ของช่องทางจะถูกตัวช่วยอวาตาร์ของ Control UI ตัดออกและแทนที่ด้วยโลโก้/ป้ายกำกับในตัว ดังนั้นช่องทางที่ถูกเจาะหรือเป็นอันตรายจึงไม่สามารถบังคับให้เบราว์เซอร์ของผู้ปฏิบัติงานดึงรูปภาพระยะไกลตามอำเภอใจได้ +- อวาตาร์และรูปภาพที่ให้บริการใต้พาธสัมพันธ์ (เช่น `/avatars/`) ยังคงแสดงผลได้ รวมถึงเส้นทางอวาตาร์ที่ต้องยืนยันตัวตนซึ่ง UI ดึงข้อมูลและแปลงเป็น URL `blob:` ภายในเครื่อง +- URL `data:image/...` แบบอินไลน์ยังคงแสดงผลได้ (มีประโยชน์สำหรับเพย์โหลดภายในโปรโตคอล) +- URL `blob:` ภายในเครื่องที่สร้างโดย UI ควบคุมยังคงแสดงผลได้ +- URL อวาตาร์ระยะไกลที่ปล่อยออกมาจากเมตาดาต้าของช่องทางจะถูกลบออกที่ตัวช่วยอวาตาร์ของ UI ควบคุม และแทนที่ด้วยโลโก้/แบดจ์ในตัว ดังนั้นช่องทางที่ถูกบุกรุกหรือประสงค์ร้ายจึงไม่สามารถบังคับให้เบราว์เซอร์ของผู้ปฏิบัติการดึงรูปภาพระยะไกลตามอำเภอใจได้ -คุณไม่จำเป็นต้องเปลี่ยนอะไรเพื่อให้ได้ลักษณะการทำงานนี้ เพราะเปิดใช้อยู่เสมอและกำหนดค่าไม่ได้ +คุณไม่จำเป็นต้องเปลี่ยนอะไรเพื่อให้ได้พฤติกรรมนี้ เพราะเปิดใช้งานเสมอและกำหนดค่าไม่ได้ -## การรับรองความถูกต้องของ route อวาตาร์ +## การยืนยันตัวตนของเส้นทางอวาตาร์ -เมื่อกำหนดค่าการรับรองความถูกต้องของ Gateway แล้ว endpoint อวาตาร์ของ Control UI จะต้องใช้โทเค็น Gateway เดียวกับ API ส่วนที่เหลือ: +เมื่อกำหนดค่าการยืนยันตัวตนของ Gateway แล้ว ปลายทางอวาตาร์ของ UI ควบคุมจะต้องใช้โทเค็น Gateway เดียวกับ API ส่วนที่เหลือ: -- `GET /avatar/` ส่งคืนรูปภาพอวาตาร์ให้เฉพาะผู้เรียกที่รับรองความถูกต้องแล้วเท่านั้น `GET /avatar/?meta=1` ส่งคืน metadata ของอวาตาร์ภายใต้กฎเดียวกัน -- คำขอที่ไม่ได้รับรองความถูกต้องไปยัง route ใด route หนึ่งจะถูกปฏิเสธ (ตรงกับ route assistant-media ข้างเคียง) สิ่งนี้ป้องกันไม่ให้ route อวาตาร์รั่วไหลข้อมูลประจำตัวของ agent บนโฮสต์ที่ได้รับการป้องกันอยู่แล้ว -- Control UI เองจะส่งต่อโทเค็น Gateway เป็นส่วนหัว bearer เมื่อดึงอวาตาร์ และใช้ URL blob ที่รับรองความถูกต้องแล้วเพื่อให้รูปภาพยังคงแสดงผลในแดชบอร์ด +- `GET /avatar/` ส่งคืนรูปภาพอวาตาร์ให้เฉพาะผู้เรียกที่ยืนยันตัวตนแล้วเท่านั้น `GET /avatar/?meta=1` ส่งคืนเมตาดาต้าอวาตาร์ภายใต้กฎเดียวกัน +- คำขอที่ไม่ได้ยืนยันตัวตนไปยังเส้นทางใดเส้นทางหนึ่งจะถูกปฏิเสธ (สอดคล้องกับเส้นทาง assistant-media ที่อยู่ข้างเคียง) ซึ่งป้องกันไม่ให้เส้นทางอวาตาร์เปิดเผยข้อมูลประจำตัวของเอเจนต์บนโฮสต์ที่ได้รับการป้องกันอยู่แล้ว +- UI ควบคุมเองจะส่งต่อโทเค็น Gateway เป็นส่วนหัว bearer เมื่อดึงอวาตาร์ และใช้ URL blob ที่ยืนยันตัวตนแล้วเพื่อให้รูปภาพยังแสดงผลในแดชบอร์ดได้ -หากคุณปิดการรับรองความถูกต้องของ Gateway (ไม่แนะนำบนโฮสต์ที่ใช้ร่วมกัน) route อวาตาร์ก็จะไม่ต้องรับรองความถูกต้องเช่นกัน สอดคล้องกับส่วนที่เหลือของ Gateway +หากคุณปิดใช้งานการยืนยันตัวตนของ Gateway (ไม่แนะนำบนโฮสต์ที่ใช้ร่วมกัน) เส้นทางอวาตาร์จะไม่ต้องยืนยันตัวตนเช่นกัน ตามแนวทางเดียวกับส่วนที่เหลือของ Gateway + +## การยืนยันตัวตนของเส้นทางสื่อผู้ช่วย + +เมื่อกำหนดค่าการยืนยันตัวตนของ Gateway แล้ว ตัวอย่างสื่อภายในเครื่องของผู้ช่วยจะใช้เส้นทางสองขั้นตอน: + +- `GET /__openclaw__/assistant-media?meta=1&source=` ต้องใช้การยืนยันตัวตนผู้ปฏิบัติการของ UI ควบคุมตามปกติ เบราว์เซอร์จะส่งโทเค็น Gateway เป็นส่วนหัว bearer เมื่อตรวจสอบความพร้อมใช้งาน +- การตอบกลับเมตาดาต้าที่สำเร็จจะมี `mediaTicket` อายุสั้นที่จำกัดขอบเขตกับพาธแหล่งที่มานั้นโดยตรง +- URL รูปภาพ เสียง วิดีโอ และเอกสารที่เบราว์เซอร์แสดงผลจะใช้ `mediaTicket=` แทนโทเค็นหรือรหัสผ่าน Gateway ที่ใช้งานอยู่ ตั๋วจะหมดอายุอย่างรวดเร็วและไม่สามารถอนุญาตแหล่งที่มาอื่นได้ + +สิ่งนี้ทำให้การแสดงผลสื่อตามปกติเข้ากันได้กับองค์ประกอบสื่อดั้งเดิมของเบราว์เซอร์ โดยไม่ใส่ข้อมูลรับรอง Gateway ที่นำกลับมาใช้ได้ซ้ำใน URL สื่อที่มองเห็นได้ ## การสร้าง UI -Gateway ให้บริการไฟล์สแตติกจาก `dist/control-ui` สร้างไฟล์เหล่านั้นด้วย: +Gateway ให้บริการไฟล์สแตติกจาก `dist/control-ui` สร้างไฟล์เหล่านี้ด้วย: ```bash pnpm ui:build ``` -ฐานแบบ absolute ที่เลือกใช้ได้ (เมื่อคุณต้องการ URL แอสเซ็ตแบบคงที่): +ฐานแบบสัมบูรณ์ที่เป็นตัวเลือก (เมื่อคุณต้องการ URL แอสเซ็ตแบบคงที่): ```bash OPENCLAW_CONTROL_UI_BASE_PATH=/openclaw/ pnpm ui:build @@ -411,11 +421,11 @@ OPENCLAW_CONTROL_UI_BASE_PATH=/openclaw/ pnpm ui:build pnpm ui:dev ``` -จากนั้นชี้ UI ไปยัง URL Gateway WS ของคุณ (เช่น `ws://127.0.0.1:18789`) +จากนั้นชี้ UI ไปที่ URL WS ของ Gateway ของคุณ (เช่น `ws://127.0.0.1:18789`) -## การดีบัก/การทดสอบ: เซิร์ฟเวอร์พัฒนา + Gateway ระยะไกล +## การดีบัก/ทดสอบ: เซิร์ฟเวอร์พัฒนา + Gateway ระยะไกล -Control UI เป็นไฟล์สแตติก เป้าหมาย WebSocket กำหนดค่าได้และอาจแตกต่างจาก HTTP origin ได้ สิ่งนี้สะดวกเมื่อคุณต้องการใช้เซิร์ฟเวอร์พัฒนา Vite ในเครื่อง แต่ให้ Gateway ทำงานที่อื่น +UI ควบคุมเป็นไฟล์สแตติก เป้าหมาย WebSocket กำหนดค่าได้และอาจแตกต่างจากต้นทาง HTTP สิ่งนี้มีประโยชน์เมื่อคุณต้องการใช้เซิร์ฟเวอร์พัฒนา Vite ภายในเครื่อง แต่ Gateway ทำงานอยู่ที่อื่น @@ -428,7 +438,7 @@ Control UI เป็นไฟล์สแตติก เป้าหมาย W http://localhost:5173/?gatewayUrl=ws%3A%2F%2F%3A18789 ``` - การรับรองความถูกต้องครั้งเดียวที่เลือกใช้ได้ (หากจำเป็น): + การยืนยันตัวตนครั้งเดียวแบบตัวเลือก (หากจำเป็น): ```text http://localhost:5173/?gatewayUrl=wss%3A%2F%2F%3A18789#token= @@ -439,17 +449,17 @@ Control UI เป็นไฟล์สแตติก เป้าหมาย W - - `gatewayUrl` จะถูกเก็บใน localStorage หลังโหลดและถูกลบออกจาก URL - - หากคุณส่ง endpoint `ws://` หรือ `wss://` แบบเต็มผ่าน `gatewayUrl` ให้เข้ารหัส URL ของค่า `gatewayUrl` เพื่อให้เบราว์เซอร์แยกวิเคราะห์ query string ได้ถูกต้อง - - ควรส่ง `token` ผ่าน fragment ของ URL (`#token=...`) เมื่อทำได้ Fragment จะไม่ถูกส่งไปยังเซิร์ฟเวอร์ จึงหลีกเลี่ยงการรั่วไหลใน request-log และ Referer พารามิเตอร์ query แบบเดิม `?token=` ยังคงถูกนำเข้าเพียงครั้งเดียวเพื่อความเข้ากันได้ แต่ใช้เป็น fallback เท่านั้น และจะถูกตัดออกทันทีหลัง bootstrap - - `password` ถูกเก็บไว้ในหน่วยความจำเท่านั้น - - เมื่อตั้งค่า `gatewayUrl` แล้ว UI จะไม่ fallback ไปยัง credential จาก config หรือ environment ให้ระบุ `token` (หรือ `password`) อย่างชัดเจน การไม่มี credential ที่ระบุอย่างชัดเจนถือเป็นข้อผิดพลาด + - `gatewayUrl` จะถูกเก็บไว้ใน localStorage หลังโหลดและถูกลบออกจาก URL + - หากคุณส่งปลายทาง `ws://` หรือ `wss://` แบบเต็มผ่าน `gatewayUrl` ให้เข้ารหัสค่า `gatewayUrl` เป็น URL เพื่อให้เบราว์เซอร์แยกวิเคราะห์ query string ได้ถูกต้อง + - ควรส่ง `token` ผ่าน fragment ของ URL (`#token=...`) เมื่อเป็นไปได้ Fragment จะไม่ถูกส่งไปยังเซิร์ฟเวอร์ ซึ่งช่วยหลีกเลี่ยงการรั่วไหลผ่านบันทึกคำขอและ Referer พารามิเตอร์ query `?token=` แบบเดิมยังคงถูกนำเข้าเพียงครั้งเดียวเพื่อความเข้ากันได้ แต่ใช้เป็นทางเลือกสำรองเท่านั้น และจะถูกลบทันทีหลัง bootstrap + - `password` จะถูกเก็บไว้ในหน่วยความจำเท่านั้น + - เมื่อกำหนด `gatewayUrl` แล้ว UI จะไม่ย้อนกลับไปใช้ข้อมูลรับรองจากค่ากำหนดหรือสภาพแวดล้อม ให้ระบุ `token` (หรือ `password`) อย่างชัดเจน การไม่มีข้อมูลรับรองที่ระบุอย่างชัดเจนถือเป็นข้อผิดพลาด - ใช้ `wss://` เมื่อ Gateway อยู่หลัง TLS (Tailscale Serve, พร็อกซี HTTPS เป็นต้น) - - `gatewayUrl` จะถูกยอมรับเฉพาะในหน้าต่างระดับบนสุดเท่านั้น (ไม่ใช่แบบฝัง) เพื่อป้องกัน clickjacking - - การปรับใช้ Control UI ที่ไม่ใช่ loopback ต้องตั้งค่า `gateway.controlUi.allowedOrigins` อย่างชัดเจน (origin แบบเต็ม) ซึ่งรวมถึงการตั้งค่าพัฒนาระยะไกลด้วย - - การเริ่มต้น Gateway อาจเติม origin ภายในเครื่อง เช่น `http://localhost:` และ `http://127.0.0.1:` จาก bind และ port ของ runtime ที่มีผล แต่ origin ของเบราว์เซอร์ระยะไกลยังคงต้องมีรายการอย่างชัดเจน - - อย่าใช้ `gateway.controlUi.allowedOrigins: ["*"]` ยกเว้นสำหรับการทดสอบภายในเครื่องที่ควบคุมอย่างเข้มงวด หมายถึงอนุญาต origin ของเบราว์เซอร์ใดก็ได้ ไม่ใช่ "จับคู่กับโฮสต์ใดก็ตามที่ฉันใช้อยู่" - - `gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback=true` เปิดใช้งานโหมด fallback ของ origin จากส่วนหัว Host แต่เป็นโหมดความปลอดภัยที่อันตราย + - `gatewayUrl` ยอมรับได้เฉพาะในหน้าต่างระดับบนสุดเท่านั้น (ไม่ใช่แบบฝัง) เพื่อป้องกัน clickjacking + - การปรับใช้ UI ควบคุมที่ไม่ใช่ loopback ต้องตั้งค่า `gateway.controlUi.allowedOrigins` อย่างชัดเจน (ต้นทางแบบเต็ม) ซึ่งรวมถึงการตั้งค่าการพัฒนาระยะไกลด้วย + - การเริ่มต้น Gateway อาจใส่ต้นทางภายในเครื่อง เช่น `http://localhost:` และ `http://127.0.0.1:` จาก bind และ port ของรันไทม์ที่มีผล แต่ต้นทางเบราว์เซอร์ระยะไกลยังคงต้องมีรายการที่ระบุไว้อย่างชัดเจน + - อย่าใช้ `gateway.controlUi.allowedOrigins: ["*"]` ยกเว้นสำหรับการทดสอบภายในเครื่องที่ควบคุมอย่างเข้มงวด หมายถึงอนุญาตต้นทางเบราว์เซอร์ใดก็ได้ ไม่ใช่ "จับคู่กับโฮสต์ใดก็ตามที่ฉันกำลังใช้" + - `gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback=true` เปิดใช้งานโหมดสำรองต้นทางจากส่วนหัว Host แต่เป็นโหมดความปลอดภัยที่อันตราย @@ -471,6 +481,6 @@ Control UI เป็นไฟล์สแตติก เป้าหมาย W ## ที่เกี่ยวข้อง - [แดชบอร์ด](/th/web/dashboard) — แดชบอร์ด Gateway -- [การตรวจสอบสถานภาพ](/th/gateway/health) — การเฝ้าระวังสถานภาพ Gateway -- [TUI](/th/web/tui) — ส่วนติดต่อผู้ใช้บนเทอร์มินัล +- [การตรวจสอบสุขภาพ](/th/gateway/health) — การตรวจสอบสุขภาพ Gateway +- [TUI](/th/web/tui) — อินเทอร์เฟซผู้ใช้แบบเทอร์มินัล - [WebChat](/th/web/webchat) — อินเทอร์เฟซแชตบนเบราว์เซอร์