Mainstream messaging
Discord
OpenClaw เชื่อมต่อกับ Discord ในฐานะบอตผ่าน Gateway อย่างเป็นทางการของ Discord รองรับทั้งข้อความส่วนตัวและช่องของเซิร์ฟเวอร์
ข้อความส่วนตัวของ Discord ใช้โหมดจับคู่เป็นค่าเริ่มต้น
ลักษณะการทำงานของคำสั่งแบบเนทีฟและรายการคำสั่ง
ขั้นตอนการวินิจฉัยและแก้ไขปัญหาที่ใช้ร่วมกันระหว่างช่อง
การตั้งค่าอย่างรวดเร็ว
สร้างแอปพลิเคชัน Discord พร้อมบอต เพิ่มบอตไปยังเซิร์ฟเวอร์ของคุณ แล้วจับคู่กับ OpenClaw หากทำได้ ให้ใช้เซิร์ฟเวอร์ส่วนตัว หากจำเป็นให้สร้างเซิร์ฟเวอร์ก่อน (Create My Own > For me and my friends)
Create a Discord application and bot
ใน Discord Developer Portal ให้คลิก New Application แล้วตั้งชื่อแอปพลิเคชัน (เช่น "OpenClaw")
เปิด Bot ในแถบด้านข้าง แล้วตั้งค่า Username เป็นชื่อเอเจนต์ของคุณ
Enable privileged intents
ขณะที่ยังอยู่ในหน้า Bot ให้เปิดใช้งานรายการต่อไปนี้ใต้ Privileged Gateway Intents:
- Message Content Intent (จำเป็น)
- Server Members Intent (แนะนำ และจำเป็นสำหรับรายการอนุญาตตามบทบาท การจับคู่ชื่อกับ ID และกลุ่มสิทธิ์เข้าถึงผู้รับสารของช่อง)
- Presence Intent (ไม่บังคับ ใช้สำหรับการอัปเดตสถานะออนไลน์เท่านั้น)
Copy your bot token
ในหน้า Bot ให้คลิก Reset Token แล้วคัดลอกโทเค็น
Generate an invite URL and add the bot to your server
เปิด OAuth2 ในแถบด้านข้าง ในส่วน OAuth2 URL Generator ให้เปิดใช้งานขอบเขตต่อไปนี้:
botapplications.commands
ในส่วน Bot Permissions ที่ปรากฏขึ้น ให้เปิดใช้งานอย่างน้อย:
General Permissions
- View Channels
Text Permissions
- Send Messages
- Read Message History
- Embed Links
- Attach Files
- Add Reactions (ไม่บังคับ)
รายการนี้เป็นสิทธิ์พื้นฐานสำหรับช่องข้อความทั่วไป หากบอตจะโพสต์ในเธรด รวมถึงเวิร์กโฟลว์ของช่องฟอรัมหรือสื่อที่สร้างหรือดำเนินเธรดต่อ ให้เปิดใช้งาน Send Messages in Threads ด้วย
คัดลอก URL ที่สร้างขึ้น เปิดในเบราว์เซอร์ เลือกเซิร์ฟเวอร์ของคุณ แล้วคลิก Continue จากนั้นบอตควรปรากฏในเซิร์ฟเวอร์ของคุณ
Enable Developer Mode and collect your IDs
ในแอป Discord ให้เปิดใช้งาน Developer Mode เพื่อให้คัดลอก ID ได้:
- User Settings (ไอคอนรูปเฟือง) → Developer → เปิด Developer Mode (บนอุปกรณ์เคลื่อนที่: App Settings → Advanced)
- คลิกขวาที่ ไอคอนเซิร์ฟเวอร์ → Copy Server ID
- คลิกขวาที่ รูปประจำตัวของคุณเอง → Copy User ID
เก็บ Server ID และ User ID ไว้กับโทเค็นบอต เพราะคุณจะต้องใช้ทั้งสามรายการในขั้นตอนถัดไป
Allow DMs from server members
เพื่อให้การจับคู่ทำงาน Discord ต้องอนุญาตให้บอตส่งข้อความส่วนตัวถึงคุณ คลิกขวาที่ ไอคอนเซิร์ฟเวอร์ → Privacy Settings → เปิด Direct Messages
เปิดการตั้งค่านี้ไว้หากคุณใช้ข้อความส่วนตัวของ Discord กับ OpenClaw หากใช้เฉพาะช่องของเซิร์ฟเวอร์ คุณสามารถปิดได้หลังจากจับคู่เสร็จแล้ว
Set your bot token securely (do not send it in chat)
โทเค็นบอตเป็นข้อมูลลับ ให้ตั้งค่าบนเครื่องที่ใช้งาน OpenClaw ก่อนส่งข้อความถึงเอเจนต์ของคุณ:
export DISCORD_BOT_TOKEN="YOUR_BOT_TOKEN"cat > discord.patch.json5 <<'JSON5'{channels: {discord: { enabled: true, token: { source: "env", provider: "default", id: "DISCORD_BOT_TOKEN" },},},}JSON5openclaw config patch --file ./discord.patch.json5 --dry-runopenclaw config patch --file ./discord.patch.json5openclaw gatewayหาก OpenClaw ทำงานเป็นบริการเบื้องหลังอยู่แล้ว ให้เริ่มการทำงานใหม่ผ่านแอป OpenClaw สำหรับ Mac หรือหยุดแล้วเริ่มกระบวนการ openclaw gateway run ใหม่
สำหรับการติดตั้งแบบบริการที่มีการจัดการ ให้เรียกใช้ openclaw gateway install จากเชลล์ที่ตั้งค่า DISCORD_BOT_TOKEN ไว้ หรือเก็บตัวแปรไว้ใน ~/.openclaw/.env เพื่อให้บริการสามารถแก้ค่า env SecretRef ได้หลังจากเริ่มการทำงานใหม่
หากโฮสต์ของคุณถูกบล็อกหรือจำกัดอัตราการเรียกใช้จากการค้นหาแอปพลิเคชันระหว่างเริ่มต้นของ Discord ให้ตั้งค่า ID แอปพลิเคชัน/ไคลเอนต์จาก Developer Portal เพื่อให้ขั้นตอนเริ่มต้นข้ามการเรียก REST นั้นได้ โดยใช้ channels.discord.applicationId สำหรับบัญชีเริ่มต้น หรือ channels.discord.accounts.<accountId>.applicationId สำหรับแต่ละบอต
Configure OpenClaw and pair
Ask your agent
สนทนากับเอเจนต์ OpenClaw ของคุณผ่านช่องที่มีอยู่แล้ว (เช่น Telegram) และแจ้งให้เอเจนต์ดำเนินการ หาก Discord เป็นช่องแรกของคุณ ให้ใช้แท็บ CLI / การกำหนดค่าแทน
"ฉันตั้งค่าโทเค็นบอต Discord ในการกำหนดค่าแล้ว โปรดตั้งค่า Discord ให้เสร็จสมบูรณ์โดยใช้ User ID
<user_id>และ Server ID<server_id>"
CLI / config
การกำหนดค่าผ่านไฟล์:
{channels: {discord: {enabled: true,token: {source: "env",provider: "default",id: "DISCORD_BOT_TOKEN",},},},}env สำรองสำหรับบัญชีเริ่มต้น:
DISCORD_BOT_TOKEN=...สำหรับการตั้งค่าด้วยสคริปต์หรือจากระยะไกล ให้เขียนบล็อก JSON5 เดียวกันด้วย openclaw config patch --file ./discord.patch.json5 --dry-run แล้วเรียกใช้อีกครั้งโดยไม่มี --dry-run นอกจากนี้ยังรองรับสตริง token แบบข้อความธรรมดา และรองรับค่า SecretRef สำหรับ channels.discord.token ผ่านผู้ให้บริการ env/file/exec โปรดดูการจัดการข้อมูลลับ
สำหรับบอต Discord หลายตัว ให้เก็บโทเค็นบอตและ ID แอปพลิเคชันของแต่ละบอตไว้ภายใต้บัญชีของบอตนั้น channels.discord.applicationId ระดับบนสุดจะถูกสืบทอดโดยบัญชีต่าง ๆ ดังนั้นให้ตั้งค่าที่ตำแหน่งนั้นเฉพาะเมื่อทุกบัญชีใช้ ID แอปพลิเคชันเดียวกัน
{channels: {discord: {enabled: true,accounts: {personal: { token: { source: "env", provider: "default", id: "DISCORD_PERSONAL_TOKEN" }, applicationId: "111111111111111111",},work: { token: { source: "env", provider: "default", id: "DISCORD_WORK_TOKEN" }, applicationId: "222222222222222222",},},},},}Approve first DM pairing
เมื่อ Gateway ทำงานแล้ว ให้ส่งข้อความส่วนตัวถึงบอตของคุณใน Discord บอตจะตอบกลับด้วยรหัสจับคู่
Ask your agent
ส่งรหัสจับคู่ให้เอเจนต์ผ่านช่องที่มีอยู่แล้ว:
"อนุมัติรหัสจับคู่ Discord นี้:
<CODE>"
CLI
openclaw pairing list discordopenclaw pairing approve discord <CODE>รหัสจับคู่จะหมดอายุหลังจาก 1 ชั่วโมง เมื่ออนุมัติแล้ว ให้สนทนากับเอเจนต์ผ่านข้อความส่วนตัวของ Discord
แนะนำ: ตั้งค่าพื้นที่ทำงานของเซิร์ฟเวอร์
เมื่อข้อความส่วนตัวทำงานแล้ว คุณสามารถเปลี่ยนเซิร์ฟเวอร์ให้เป็นพื้นที่ทำงานเต็มรูปแบบ ซึ่งแต่ละช่องมีเซสชันเอเจนต์และบริบทแยกเป็นของตนเอง แนะนำสำหรับเซิร์ฟเวอร์ส่วนตัวที่มีเพียงคุณและบอตของคุณ
Add your server to the guild allowlist
การดำเนินการนี้ช่วยให้เอเจนต์ตอบกลับได้ในทุกช่องบนเซิร์ฟเวอร์ของคุณ ไม่ใช่เฉพาะข้อความส่วนตัว
Ask your agent
"เพิ่ม Server ID ของ Discord
<server_id>ของฉันไปยังรายการอนุญาตของเซิร์ฟเวอร์"
Config
{channels: {discord: {groupPolicy: "allowlist",guilds: {YOUR_SERVER_ID: { requireMention: true, users: ["YOUR_USER_ID"],},},},},}Allow responses without @mention
โดยค่าเริ่มต้น เอเจนต์จะตอบกลับในช่องของเซิร์ฟเวอร์เฉพาะเมื่อถูก @กล่าวถึงเท่านั้น สำหรับเซิร์ฟเวอร์ส่วนตัว คุณอาจต้องการให้เอเจนต์ตอบทุกข้อความ
ในช่องของเซิร์ฟเวอร์ การตอบกลับปกติจะถูกโพสต์โดยอัตโนมัติตามค่าเริ่มต้น สำหรับห้องที่ใช้ร่วมกันและเปิดตลอดเวลา ให้เลือกใช้ messages.groupChat.visibleReplies: "message_tool" เพื่อให้เอเจนต์เฝ้าดูอยู่เงียบ ๆ และโพสต์เฉพาะเมื่อพิจารณาว่าการตอบกลับในช่องมีประโยชน์ วิธีนี้ทำงานได้ดีที่สุดกับโมเดลรุ่นล่าสุดที่ใช้เครื่องมือได้อย่างน่าเชื่อถือ เช่น GPT-5.6 Sol เหตุการณ์ห้องโดยรอบจะไม่ส่งเสียงรบกวน เว้นแต่เครื่องมือจะส่งข้อความ โปรดดูเหตุการณ์ห้องโดยรอบสำหรับการกำหนดค่าโหมดเฝ้าดูอย่างครบถ้วน
หาก Discord แสดงสถานะกำลังพิมพ์และบันทึกแสดงการใช้โทเค็น แต่ไม่มีข้อความถูกโพสต์ ให้ตรวจสอบว่ารอบการทำงานนั้นได้รับการกำหนดค่าเป็นเหตุการณ์ห้องโดยรอบหรือเลือกใช้การตอบกลับที่มองเห็นได้ผ่านเครื่องมือส่งข้อความหรือไม่
Ask your agent
"อนุญาตให้เอเจนต์ของฉันตอบกลับบนเซิร์ฟเวอร์นี้โดยไม่ต้องถูก @กล่าวถึง"
Config
ตั้งค่า requireMention: false ในการกำหนดค่าเซิร์ฟเวอร์ของคุณ:
{channels: {discord: {guilds: {YOUR_SERVER_ID: { requireMention: false,},},},},}หากต้องการบังคับให้การตอบกลับแบบกลุ่ม/ช่องที่มองเห็นได้ส่งผ่านเครื่องมือส่งข้อความ ให้ตั้งค่า messages.groupChat.visibleReplies: "message_tool"
Plan for memory in guild channels
หน่วยความจำระยะยาว (MEMORY.md) จะโหลดโดยอัตโนมัติเฉพาะในเซสชันข้อความส่วนตัว เซสชันในช่องของเซิร์ฟเวอร์จะไม่โหลดไฟล์นี้
Ask your agent
"เมื่อฉันถามคำถามในช่อง Discord ให้ใช้ memory_search หรือ memory_get หากต้องการบริบทระยะยาวจาก MEMORY.md"
Manual
สำหรับบริบทที่ใช้ร่วมกันในทุกช่อง ให้ใส่คำสั่งที่คงที่ไว้ใน AGENTS.md หรือ USER.md (ระบบจะแทรกให้ทุกเซสชัน) เก็บบันทึกระยะยาวไว้ใน MEMORY.md และเข้าถึงเมื่อต้องการด้วยเครื่องมือหน่วยความจำ
ตอนนี้ให้สร้างช่องและเริ่มสนทนา เอเจนต์จะเห็นชื่อช่อง และแต่ละช่องเป็นเซสชันที่แยกจากกัน คุณสามารถตั้งค่า #coding, #home, #research หรือช่องใด ๆ ที่เหมาะกับเวิร์กโฟลว์ของคุณ
โมเดลรันไทม์
- Gateway เป็นเจ้าของการเชื่อมต่อ Discord
- การกำหนดเส้นทางตอบกลับเป็นแบบตายตัว: ข้อความขาเข้าจาก Discord จะตอบกลับไปยัง Discord
- ระบบจะเพิ่มข้อมูลเมตาของเซิร์ฟเวอร์/ช่อง Discord ลงในพรอมต์ของโมเดลในฐานะบริบทที่ไม่น่าเชื่อถือ ไม่ใช่คำนำหน้าคำตอบที่ผู้ใช้มองเห็น หากโมเดลคัดลอกกรอบข้อมูลนั้นกลับมา OpenClaw จะนำข้อมูลเมตาที่คัดลอกออกจากคำตอบขาออกและบริบทสำหรับการเล่นซ้ำในอนาคต
- โดยค่าเริ่มต้น (
session.dmScope=main) การสนทนาโดยตรงจะใช้เซสชันหลักของเอเจนต์ร่วมกัน (agent:main:main) - ช่องของเซิร์ฟเวอร์ใช้คีย์เซสชันที่แยกจากกัน (
agent:<agentId>:discord:channel:<channelId>) - ข้อความส่วนตัวแบบกลุ่มจะถูกละเว้นโดยค่าเริ่มต้น (
channels.discord.dm.groupEnabled=false) - คำสั่งสแลชแบบเนทีฟทำงานในเซสชันคำสั่งที่แยกจากกัน (
agent:<agentId>:discord:slash:<userId>) โดยยังคงส่งCommandTargetSessionKeyไปยังเซสชันการสนทนาที่กำหนดเส้นทางไว้ - การส่งประกาศ Cron/Heartbeat แบบข้อความล้วนไปยัง Discord จะยุบเหลือเพียงคำตอบสุดท้ายที่ผู้ช่วยมองเห็นและส่งเพียงครั้งเดียว เพย์โหลดสื่อและคอมโพเนนต์แบบมีโครงสร้างจะยังคงส่งเป็นหลายข้อความเมื่อเอเจนต์สร้างเพย์โหลดที่ส่งมอบได้หลายรายการ
ช่องฟอรัม
ช่องฟอรัมและช่องสื่อของ Discord รับเฉพาะโพสต์ในเธรด OpenClaw รองรับการสร้างโพสต์ดังกล่าวสองวิธี:
- ส่งข้อความไปยังฟอรัมแม่ (
channel:<forumId>) เพื่อสร้างเธรดโดยอัตโนมัติ ชื่อเธรดจะใช้บรรทัดแรกที่ไม่ว่างของข้อความ (ตัดให้ไม่เกินขีดจำกัดชื่อเธรด 100 อักขระของ Discord) - ใช้
openclaw message thread createเพื่อสร้างเธรดโดยตรง อย่าส่ง--message-idสำหรับช่องฟอรัม
ส่งไปยังฟอรัมแม่เพื่อสร้างเธรด:
openclaw message send --channel discord --target channel:<forumId> \ --message "Topic title\nBody of the post"สร้างเธรดฟอรัมอย่างชัดเจน:
openclaw message thread create --channel discord --target channel:<forumId> \ --thread-name "Topic title" --message "Body of the post"ฟอรัมแม่ไม่รองรับคอมโพเนนต์ของ Discord หากต้องการใช้คอมโพเนนต์ ให้ส่งไปยังตัวเธรดโดยตรง (channel:<threadId>)
คอมโพเนนต์แบบโต้ตอบ
OpenClaw รองรับคอนเทนเนอร์คอมโพเนนต์ v2 ของ Discord สำหรับข้อความจากเอเจนต์ ใช้เครื่องมือส่งข้อความพร้อมเพย์โหลด components ผลลัพธ์จากการโต้ตอบจะถูกส่งกลับไปยังเอเจนต์ในรูปแบบข้อความขาเข้าปกติ และเป็นไปตามการตั้งค่า replyToMode ของ Discord ที่มีอยู่
บล็อกที่รองรับ:
text,section,separator,actions,media-gallery,file- แถวการดำเนินการรองรับปุ่มสูงสุด 5 ปุ่ม หรือเมนูเลือกหนึ่งรายการ
- ประเภทการเลือก:
string,user,role,mentionable,channel
ตามค่าเริ่มต้น คอมโพเนนต์จะใช้ได้ครั้งเดียว ตั้งค่า components.reusable=true เพื่อให้สามารถใช้ปุ่ม เมนูเลือก และแบบฟอร์มได้หลายครั้งจนกว่าจะหมดอายุ
หากต้องการจำกัดผู้ที่สามารถคลิกปุ่มได้ ให้ตั้งค่า allowedUsers บนปุ่มนั้น (รหัสผู้ใช้ Discord, แท็ก หรือ *) ผู้ใช้ที่ไม่ตรงเงื่อนไขจะได้รับข้อความปฏิเสธแบบชั่วคราวที่มองเห็นได้เฉพาะตนเอง
โดยค่าเริ่มต้น คอลแบ็กของคอมโพเนนต์จะหมดอายุหลังจาก 30 นาที ตั้งค่า channels.discord.agentComponents.ttlMs เพื่อเปลี่ยนอายุของรีจิสทรีคอลแบ็กสำหรับบัญชีเริ่มต้น หรือกำหนด channels.discord.accounts.<accountId>.agentComponents.ttlMs แยกตามบัญชี ค่านี้มีหน่วยเป็นมิลลิวินาที ต้องเป็นจำนวนเต็มบวก และมีค่าสูงสุด 86400000 (24 ชั่วโมง) ค่า TTL ที่ยาวขึ้นเหมาะกับเวิร์กโฟลว์การตรวจสอบ/อนุมัติที่ต้องการให้ปุ่มยังคงใช้งานได้ แต่จะขยายช่วงเวลาที่ข้อความ Discord เก่ายังสามารถทริกเกอร์การดำเนินการได้ ควรใช้ TTL ที่สั้นที่สุดซึ่งเพียงพอต่อการใช้งาน และคงค่าเริ่มต้นไว้หากคอลแบ็กเก่าอาจทำให้เกิดพฤติกรรมที่ไม่คาดคิด
คำสั่งแบบสแลช /model และ /models จะเปิดตัวเลือกโมเดลแบบโต้ตอบ ซึ่งมีรายการแบบเลื่อนลงสำหรับผู้ให้บริการ โมเดล และรันไทม์ที่เข้ากันได้ พร้อมขั้นตอน Submit คำสั่ง /models add เลิกใช้งานแล้ว และจะส่งคืนข้อความแจ้งการเลิกใช้งานแทนการลงทะเบียนโมเดลจากแชต การตอบกลับของตัวเลือกเป็นแบบชั่วคราวที่มองเห็นได้เฉพาะตนเอง และใช้งานได้เฉพาะผู้ใช้ที่เรียกคำสั่ง เมนูเลือกของ Discord จำกัดไว้ที่ 25 ตัวเลือก ดังนั้นให้เพิ่มรายการ provider/* ลงใน agents.defaults.models เมื่อต้องการให้ตัวเลือกแสดงโมเดลที่ค้นพบแบบไดนามิกเฉพาะสำหรับผู้ให้บริการที่เลือก เช่น openai หรือ vllm
ไฟล์แนบ:
- บล็อก
fileต้องชี้ไปยังการอ้างอิงไฟล์แนบ (attachment://<filename>) - ระบุไฟล์แนบผ่าน
media/path/filePath(ไฟล์เดียว) ใช้media-galleryสำหรับหลายไฟล์ - ใช้
filenameเพื่อแทนที่ชื่อไฟล์ที่อัปโหลด เมื่อต้องการให้ชื่อตรงกับการอ้างอิงไฟล์แนบ
แบบฟอร์มโมดัล:
- เพิ่ม
components.modalโดยมีฟิลด์ได้สูงสุด 5 ฟิลด์ - ประเภทฟิลด์:
text,checkbox,radio,select,role-select,user-select - OpenClaw จะเพิ่มปุ่มทริกเกอร์ให้อัตโนมัติ
ตัวอย่าง:
{ channel: "discord", action: "send", to: "channel:123456789012345678", message: "Optional fallback text", components: { reusable: true, text: "Choose a path", blocks: [ { type: "actions", buttons: [ { label: "Approve", style: "success", allowedUsers: ["123456789012345678"], }, { label: "Decline", style: "danger" }, ], }, { type: "actions", select: { type: "string", placeholder: "Pick an option", options: [ { label: "Option A", value: "a" }, { label: "Option B", value: "b" }, ], }, }, ], modal: { title: "Details", triggerLabel: "Open form", fields: [ { type: "text", label: "Requester" }, { type: "select", label: "Priority", options: [ { label: "Low", value: "low" }, { label: "High", value: "high" }, ], }, ], }, },}การควบคุมการเข้าถึงและการกำหนดเส้นทาง
DM policy
channels.discord.dmPolicy ควบคุมการเข้าถึง DM ส่วน channels.discord.allowFrom คือรายการอนุญาต DM หลัก
pairing(ค่าเริ่มต้น)allowlist(ต้องมีผู้ส่งอย่างน้อยหนึ่งรายในallowFrom)open(กำหนดให้channels.discord.allowFromต้องมี"*")disabled
หากนโยบาย DM ไม่ใช่แบบเปิด ผู้ใช้ที่ไม่รู้จักจะถูกบล็อก (หรือได้รับข้อความแจ้งให้จับคู่ในโหมด pairing)
ลำดับความสำคัญสำหรับหลายบัญชี:
channels.discord.accounts.default.allowFromใช้กับบัญชีdefaultเท่านั้น- สำหรับหนึ่งบัญชี
allowFromมีลำดับความสำคัญเหนือdm.allowFromแบบเดิม - บัญชีที่มีชื่อจะสืบทอด
channels.discord.allowFromเมื่อไม่ได้ตั้งค่าทั้งallowFromของบัญชีนั้นและdm.allowFromแบบเดิม - บัญชีที่มีชื่อจะไม่สืบทอด
channels.discord.accounts.default.allowFrom
ระบบยังคงอ่าน channels.discord.dm.policy และ channels.discord.dm.allowFrom แบบเดิมเพื่อความเข้ากันได้ openclaw doctor --fix จะย้ายค่าเหล่านี้ไปยัง dmPolicy และ allowFrom เมื่อสามารถทำได้โดยไม่เปลี่ยนแปลงการเข้าถึง
รูปแบบเป้าหมาย DM สำหรับการส่ง:
user:<id>- การกล่าวถึง
<@id>
โดยปกติ รหัสตัวเลขล้วนจะถูกตีความเป็นรหัสช่องเมื่อมีค่าเริ่มต้นของช่องทำงานอยู่ แต่รหัสที่อยู่ใน allowFrom สำหรับ DM ที่มีผลของบัญชีจะถูกตีความเป็นเป้าหมาย DM ของผู้ใช้เพื่อความเข้ากันได้
Access groups
DM ของ Discord และการอนุญาตคำสั่งข้อความสามารถใช้รายการแบบไดนามิก accessGroup:<name> ใน channels.discord.allowFrom
ชื่อกลุ่มการเข้าถึงใช้ร่วมกันในทุกช่องข้อความ ใช้ type: "message.senders" สำหรับกลุ่มแบบคงที่ซึ่งระบุสมาชิกด้วยไวยากรณ์ allowFrom ปกติของแต่ละช่อง หรือใช้ type: "discord.channelAudience" เมื่อต้องการให้กลุ่มผู้ใช้ที่มีสิทธิ์ ViewChannel ในปัจจุบันของช่อง Discord เป็นตัวกำหนดสมาชิกแบบไดนามิก พฤติกรรมร่วมของกลุ่มการเข้าถึง: กลุ่มการเข้าถึง
{accessGroups: {operators: { type: "message.senders", members: { "*": ["global-owner-id"], discord: ["discord:123456789012345678"], telegram: ["987654321"], },},},channels: {discord: { dmPolicy: "allowlist", allowFrom: ["accessGroup:operators"],},},}ช่องข้อความ Discord ไม่มีรายชื่อสมาชิกแยกต่างหาก type: "discord.channelAudience" กำหนดรูปแบบสมาชิกดังนี้: ผู้ส่ง DM เป็นสมาชิกของกิลด์ที่กำหนดค่าไว้ และมีสิทธิ์ ViewChannel ที่มีผลอยู่ในปัจจุบันบนช่องที่กำหนดค่า หลังจากใช้บทบาทและการเขียนทับสิทธิ์ของช่องแล้ว
ตัวอย่าง: อนุญาตให้ทุกคนที่มองเห็น #maintainers ส่ง DM ถึงบอตได้ ขณะที่ยังคงปิด DM สำหรับบุคคลอื่นทั้งหมด
{accessGroups: {maintainers: { type: "discord.channelAudience", guildId: "1456350064065904867", channelId: "1456744319972282449", membership: "canViewChannel",},},channels: {discord: { dmPolicy: "allowlist", allowFrom: ["accessGroup:maintainers"],},},}คุณสามารถผสมรายการแบบไดนามิกและแบบคงที่ได้:
{accessGroups: {maintainers: { type: "discord.channelAudience", guildId: "1456350064065904867", channelId: "1456744319972282449",},},channels: {discord: { dmPolicy: "allowlist", allowFrom: ["accessGroup:maintainers", "discord:123456789012345678"],},},}การค้นหาจะปฏิเสธการเข้าถึงเมื่อเกิดข้อผิดพลาด หาก Discord ส่งคืน Missing Access การค้นหาสมาชิกล้มเหลว หรือช่องเป็นของกิลด์อื่น ผู้ส่ง DM จะถูกถือว่าไม่มีสิทธิ์
เปิดใช้ Server Members Intent ใน Discord Developer Portal เมื่อใช้กลุ่มการเข้าถึงตามกลุ่มผู้ใช้ของช่อง เนื่องจาก DM ไม่มีสถานะสมาชิกกิลด์ OpenClaw จึงค้นหาสมาชิกผ่าน Discord REST ในขณะตรวจสอบสิทธิ์
Guild policy
การจัดการกิลด์ควบคุมโดย channels.discord.groupPolicy:
openallowlistdisabled
ค่าพื้นฐานที่ปลอดภัยเมื่อมี channels.discord คือ allowlist
พฤติกรรมของ allowlist:
- กิลด์ต้องตรงกับ
channels.discord.guilds(แนะนำให้ใช้idและรองรับ slug) - รายการอนุญาตผู้ส่งแบบไม่บังคับ:
users(แนะนำให้ใช้รหัสที่คงที่) และroles(รหัสบทบาทเท่านั้น) หากกำหนดค่าอย่างใดอย่างหนึ่ง ผู้ส่งจะได้รับอนุญาตเมื่อตรงกับusersหรือroles - การจับคู่ชื่อ/แท็กโดยตรงถูกปิดใช้งานตามค่าเริ่มต้น เปิดใช้
channels.discord.dangerouslyAllowNameMatching: trueเฉพาะเป็นโหมดความเข้ากันได้ฉุกเฉินเท่านั้น usersรองรับชื่อ/แท็ก แต่รหัสปลอดภัยกว่าopenclaw security auditจะแจ้งเตือนเมื่อใช้รายการชื่อ/แท็ก- หากกิลด์กำหนดค่า
channelsไว้ ช่องที่ไม่อยู่ในรายการจะถูกปฏิเสธ - หากกิลด์ไม่มีบล็อก
channelsช่องทั้งหมดในกิลด์ที่อยู่ในรายการอนุญาตจะได้รับอนุญาต
ตัวอย่าง:
{channels: {discord: { groupPolicy: "allowlist", guilds: { "123456789012345678": { requireMention: true, ignoreOtherMentions: true, users: ["987654321098765432"], roles: ["123456789012345678"], channels: { general: { enabled: true }, help: { enabled: true, requireMention: true }, }, }, },},},}คีย์ allow แบบเดิมที่กำหนดแยกตามช่องจะถูกย้ายไปเป็น enabled โดย openclaw doctor --fix
หากคุณตั้งค่าเฉพาะ DISCORD_BOT_TOKEN และไม่ได้สร้างบล็อก channels.discord ค่าสำรองขณะรันไทม์คือ groupPolicy="allowlist" (พร้อมคำเตือนในบันทึก) แม้ว่า channels.defaults.groupPolicy จะเป็น open
Mentions and group DMs
โดยค่าเริ่มต้น ข้อความในกิลด์ต้องมีการกล่าวถึง
การตรวจจับการกล่าวถึงประกอบด้วย:
- การกล่าวถึงบอตอย่างชัดเจน
- รูปแบบการกล่าวถึงที่กำหนดค่าไว้ (
agents.list[].groupChat.mentionPatternsโดยใช้messages.groupChat.mentionPatternsเป็นค่าสำรอง) - พฤติกรรมการตอบกลับถึงบอตโดยนัยในกรณีที่รองรับ
เมื่อเขียนข้อความขาออกของ Discord ให้ใช้ไวยากรณ์การกล่าวถึงมาตรฐาน: <@USER_ID> สำหรับผู้ใช้ <#CHANNEL_ID> สำหรับช่อง และ <@&ROLE_ID> สำหรับบทบาท อย่าใช้รูปแบบการกล่าวถึงชื่อเล่นแบบเดิม <@!USER_ID>
กำหนดค่า requireMention แยกตามกิลด์/ช่อง (channels.discord.guilds...)
ignoreOtherMentions สามารถเลือกให้ละทิ้งข้อความที่กล่าวถึงผู้ใช้/บทบาทอื่นแต่ไม่ได้กล่าวถึงบอต (ไม่รวม @everyone/@here)
DM แบบกลุ่ม:
- ค่าเริ่มต้น: ไม่สนใจ (
dm.groupEnabled=false) - รายการอนุญาตแบบไม่บังคับผ่าน
dm.groupChannels(รหัสช่องหรือ slug)
การกำหนดเส้นทางเอเจนต์ตามบทบาท
ใช้ bindings[].match.roles เพื่อกำหนดเส้นทางสมาชิกกิลด์ Discord ไปยังเอเจนต์ต่าง ๆ ตามรหัสบทบาท การผูกตามบทบาทรองรับเฉพาะรหัสบทบาท และจะถูกประเมินหลังการผูกแบบเพียร์หรือเพียร์แม่ แต่ก่อนการผูกเฉพาะกิลด์ หากการผูกกำหนดฟิลด์จับคู่อื่นด้วย (เช่น peer + guildId + roles) ฟิลด์ที่กำหนดค่าทั้งหมดต้องตรงกัน
{ bindings: [ { agentId: "opus", match: { channel: "discord", guildId: "123456789012345678", roles: ["111111111111111111"], }, }, { agentId: "sonnet", match: { channel: "discord", guildId: "123456789012345678", }, }, ],}คำสั่งเนทีฟและการตรวจสอบสิทธิ์คำสั่ง
commands.nativeมีค่าเริ่มต้นเป็น"auto"และเปิดใช้งานสำหรับ Discord- การเขียนทับแยกตามช่องทาง:
channels.discord.commands.native commands.native=falseจะข้ามการลงทะเบียนและการล้างคำสั่งแบบสแลชของ Discord ระหว่างการเริ่มต้นระบบ คำสั่งที่ลงทะเบียนไว้ก่อนหน้านี้อาจยังปรากฏใน Discord จนกว่าคุณจะลบออกจากแอป Discord- การยืนยันสิทธิ์ของคำสั่งเนทีฟใช้รายการอนุญาต/นโยบายของ Discord ชุดเดียวกับการจัดการข้อความปกติ
- คำสั่งอาจยังปรากฏใน UI ของ Discord สำหรับผู้ใช้ที่ไม่ได้รับอนุญาต แต่เมื่อเรียกใช้งาน OpenClaw จะบังคับใช้การยืนยันสิทธิ์และตอบว่า "ไม่ได้รับอนุญาต"
- การตั้งค่าเริ่มต้นของคำสั่งแบบสแลช:
ephemeral: true(channels.discord.slashCommand.ephemeral)
ดูแค็ตตาล็อกและลักษณะการทำงานของคำสั่งได้ที่ คำสั่งแบบสแลช
รายละเอียดฟีเจอร์
แท็กการตอบกลับและการตอบกลับแบบเนทีฟ
Discord รองรับแท็กการตอบกลับในเอาต์พุตของเอเจนต์:
[[reply_to_current]][[reply_to:<id>]]
ควบคุมด้วย channels.discord.replyToMode:
off(ค่าเริ่มต้น): ไม่มีการจัดเธรดการตอบกลับโดยนัย แต่ยังคงใช้แท็ก[[reply_to_*]]ที่ระบุอย่างชัดเจนfirst: แนบการอ้างอิงการตอบกลับแบบเนทีฟโดยนัยกับข้อความ Discord ขาออกข้อความแรกของรอบall: แนบกับข้อความขาออกทุกข้อความbatched: แนบเฉพาะเมื่อเหตุการณ์ขาเข้าเป็นชุดข้อความหลายรายการที่ผ่านการหน่วงเพื่อลดการเรียกซ้ำ เหมาะเมื่อคุณต้องการการตอบกลับแบบเนทีฟเป็นหลักสำหรับการสนทนาที่ส่งข้อความถี่และกำกวม ไม่ใช่ทุกรอบที่มีข้อความเดียว
รหัสข้อความจะแสดงในบริบท/ประวัติ เพื่อให้เอเจนต์ระบุเป้าหมายเป็นข้อความเฉพาะได้
ตัวอย่างลิงก์
โดยค่าเริ่มต้น Discord จะสร้างเนื้อหาฝังแบบสมบูรณ์สำหรับ URL ส่วน OpenClaw จะระงับเนื้อหาฝังที่สร้างขึ้นเหล่านั้นในข้อความ Discord ขาออกโดยค่าเริ่มต้น ดังนั้น URL ที่เอเจนต์ส่งจะยังคงเป็นลิงก์ธรรมดา เว้นแต่คุณจะเลือกเปิดใช้:
{channels: {discord: { suppressEmbeds: false,},},}ตั้งค่า channels.discord.accounts.<id>.suppressEmbeds เพื่อเขียนทับสำหรับบัญชีหนึ่งบัญชี การส่งผ่านเครื่องมือข้อความของเอเจนต์สามารถส่ง suppressEmbeds: false สำหรับข้อความเดียวได้เช่นกัน เพย์โหลด embeds ของ Discord ที่ระบุอย่างชัดเจนจะไม่ถูกระงับโดยการตั้งค่าตัวอย่างลิงก์เริ่มต้น
ตัวอย่างสตรีมสด
OpenClaw สามารถสตรีมร่างคำตอบโดยส่งข้อความชั่วคราวและแก้ไขข้อความนั้นเมื่อข้อความเข้ามา channels.discord.streaming.mode รับค่า off | partial | block | progress (ค่าเริ่มต้นเมื่อไม่ได้ตั้งค่าคีย์ streaming/streamMode แบบเดิม) streamMode เป็นนามแฝงแบบเดิม ให้เรียกใช้ openclaw doctor --fix เพื่อเขียนการกำหนดค่าที่บันทึกไว้ใหม่ให้อยู่ในรูปแบบ streaming แบบซ้อนที่เป็นมาตรฐาน
{channels: {discord: { streaming: { mode: "progress", progress: { label: "auto", maxLines: 8, maxLineChars: 120, toolProgress: true, commentary: false, }, },},},}offปิดการแก้ไขตัวอย่าง Discordpartialแก้ไขข้อความตัวอย่างข้อความเดียวเมื่อโทเค็นเข้ามาblockส่งส่วนข้อความขนาดเท่าร่าง ปรับขนาดและจุดแบ่งด้วยstreaming.preview.chunk(minChars,maxChars,breakPreference) โดยจะถูกจำกัดไม่ให้เกินtextChunkLimitเมื่อเปิดใช้การสตรีมแบบบล็อกอย่างชัดเจน OpenClaw จะข้ามสตรีมตัวอย่างเพื่อหลีกเลี่ยงการสตรีมซ้ำซ้อนprogressเก็บร่างสถานะที่แก้ไขได้หนึ่งรายการและอัปเดตด้วยความคืบหน้าของเครื่องมือจนกว่าจะส่งผลลัพธ์สุดท้าย ป้ายเริ่มต้นที่ใช้ร่วมกันเป็นบรรทัดที่เลื่อนต่อเนื่อง จึงจะเลื่อนหายไปเหมือนส่วนอื่นเมื่อมีรายละเอียดงานมากพอ- ผลลัพธ์สุดท้ายที่เป็นสื่อ ข้อผิดพลาด และการตอบกลับที่ระบุอย่างชัดเจนจะยกเลิกการแก้ไขตัวอย่างที่รอดำเนินการ
streaming.preview.toolProgress(ค่าเริ่มต้นtrue) ควบคุมว่าการอัปเดตเครื่องมือ/ความคืบหน้าจะใช้ข้อความตัวอย่างซ้ำหรือไม่- แถวเครื่องมือ/ความคืบหน้าจะแสดงในรูปแบบกระชับเป็นอีโมจิ + ชื่อเรื่อง + รายละเอียดเมื่อมี เช่น
🛠️ Bash: เรียกใช้การทดสอบหรือ🔎 Web Search: สำหรับ "คำค้น" streaming.progress.commentary(ค่าเริ่มต้นfalse) ใช้เลือกให้รวมข้อความคำอธิบาย/ข้อความนำของผู้ช่วยในร่างความคืบหน้าชั่วคราว ข้อความคำอธิบายจะถูกทำความสะอาดก่อนแสดงผล ยังคงเป็นข้อมูลชั่วคราว และไม่เปลี่ยนแปลงการส่งคำตอบสุดท้ายstreaming.progress.maxLineCharsควบคุมโควตาตัวอย่างความคืบหน้าต่อบรรทัด ข้อความร้อยแก้วจะถูกย่อที่ขอบเขตคำ ส่วนรายละเอียดคำสั่งและพาธจะคงส่วนท้ายที่มีประโยชน์ไว้streaming.preview.commandText/streaming.progress.commandTextควบคุมรายละเอียดคำสั่ง/การดำเนินการในบรรทัดความคืบหน้าแบบกระชับ:raw(ค่าเริ่มต้น) หรือstatus(เฉพาะป้ายเครื่องมือ)
ซ่อนข้อความคำสั่ง/การดำเนินการดิบ โดยยังคงแสดงบรรทัดความคืบหน้าแบบกระชับ:
{ "channels": { "discord": { "streaming": { "mode": "progress", "progress": { "toolProgress": true, "commandText": "status" } } } }}การสตรีมตัวอย่างรองรับเฉพาะข้อความ การตอบกลับที่มีสื่อจะกลับไปใช้การส่งตามปกติ
ประวัติ บริบท และลักษณะการทำงานของเธรด
บริบทประวัติกิลด์:
- ค่าเริ่มต้นของ
channels.discord.historyLimitคือ20 - ค่าสำรอง:
messages.groupChat.historyLimit 0หมายถึงปิดใช้งาน
การควบคุมประวัติข้อความส่วนตัว:
channels.discord.dmHistoryLimitchannels.discord.dms["<user_id>"].historyLimit
ลักษณะการทำงานของเธรด:
- เธรด Discord จะถูกกำหนดเส้นทางเป็นเซสชันของช่องและสืบทอดการกำหนดค่าของช่องแม่ เว้นแต่จะมีการเขียนทับ
- เซสชันเธรดสืบทอดการเลือก
/modelระดับเซสชันของช่องแม่เป็นค่าสำรองเฉพาะโมเดล การเลือก/modelภายในเธรดมีลำดับความสำคัญสูงกว่า และจะไม่คัดลอกประวัติทรานสคริปต์ของช่องแม่ เว้นแต่จะเปิดใช้การสืบทอดทรานสคริปต์ channels.discord.thread.inheritParent(ค่าเริ่มต้นfalse) เลือกให้เธรดอัตโนมัติใหม่เริ่มต้นด้วยทรานสคริปต์จากช่องแม่ การเขียนทับแยกตามบัญชี:channels.discord.accounts.<id>.thread.inheritParent- รีแอ็กชันจากเครื่องมือข้อความสามารถจำแนกเป้าหมายข้อความส่วนตัว
user:<id>ได้ guilds.<guild>.channels.<channel>.requireMention: falseจะยังคงอยู่ระหว่างการใช้ค่าสำรองเพื่อเปิดใช้งานในขั้นตอนการตอบกลับ
หัวข้อช่องจะถูกแทรกเป็นบริบทที่ ไม่น่าเชื่อถือ รายการอนุญาตควบคุมว่าใครสามารถเรียกเอเจนต์ได้ ไม่ใช่ขอบเขตการปกปิดบริบทเสริมทั้งหมด
เซสชันที่ผูกกับเธรดสำหรับเอเจนต์ย่อย
Discord สามารถผูกเธรดกับเป้าหมายเซสชัน เพื่อให้ข้อความติดตามผลในเธรดนั้นยังคงถูกกำหนดเส้นทางไปยังเซสชันเดิม (รวมถึงเซสชันของเอเจนต์ย่อย)
คำสั่ง:
/focus <target>ผูกเธรดปัจจุบัน/เธรดใหม่กับเป้าหมายเอเจนต์ย่อย/เซสชัน/unfocusลบการผูกเธรดปัจจุบัน/agentsแสดงการทำงานที่ใช้งานอยู่และสถานะการผูก/session idle <duration|off>ตรวจสอบ/อัปเดตการยกเลิกการโฟกัสอัตโนมัติเมื่อไม่มีการใช้งานสำหรับการผูกที่โฟกัสอยู่/session max-age <duration|off>ตรวจสอบ/อัปเดตอายุสูงสุดแบบตายตัวสำหรับการผูกที่โฟกัสอยู่
การกำหนดค่า:
{session: {threadBindings: { enabled: true, idleHours: 24, maxAgeHours: 0,},},channels: {discord: { threadBindings: { enabled: true, idleHours: 24, maxAgeHours: 0, spawnSessions: true, defaultSpawnContext: "fork", },},},}หมายเหตุ:
session.threadBindings.*กำหนดค่าเริ่มต้นส่วนกลาง ส่วนchannels.discord.threadBindings.*เขียนทับลักษณะการทำงานของ DiscordspawnSessionsควบคุมการสร้าง/ผูกเธรดอัตโนมัติสำหรับsessions_spawn({ thread: true })และการสร้างเธรด ACP ค่าเริ่มต้น:truedefaultSpawnContextควบคุมบริบทเนทีฟของเอเจนต์ย่อยสำหรับการสร้างที่ผูกกับเธรด ค่าเริ่มต้น:"fork"- คีย์
spawnSubagentSessions/spawnAcpSessionsที่เลิกใช้แล้วจะถูกย้ายข้อมูลโดยopenclaw doctor --fix - หากปิดใช้การผูกเธรดสำหรับบัญชีหนึ่ง
/focusและการดำเนินการผูกเธรดที่เกี่ยวข้องจะไม่พร้อมใช้งาน
การผูกช่อง ACP แบบถาวร
สำหรับพื้นที่ทำงาน ACP แบบ "เปิดตลอดเวลา" ที่มีความเสถียร ให้กำหนดค่าการผูก ACP แบบระบุชนิดในระดับบนสุด โดยกำหนดเป้าหมายไปยังการสนทนา Discord
พาธการกำหนดค่า: bindings[] ที่มี type: "acp" และ match.channel: "discord"
{agents: {list: [ { id: "codex", runtime: { type: "acp", acp: { agent: "codex", backend: "acpx", mode: "persistent", cwd: "/workspace/openclaw", }, }, },],},bindings: [{ type: "acp", agentId: "codex", match: { channel: "discord", accountId: "default", peer: { kind: "channel", id: "222222222222222222" }, }, acp: { label: "codex-main" },},],channels: {discord: { guilds: { "111111111111111111": { channels: { "222222222222222222": { requireMention: false, }, }, }, },},},}หมายเหตุ:
/acp spawn codex --bind hereผูกช่องหรือเธรดปัจจุบันไว้กับตำแหน่งเดิม และทำให้ข้อความในอนาคตใช้เซสชัน ACP เดิมต่อไป ข้อความในเธรดสืบทอดการผูกของช่องแม่- ในช่องหรือเธรดที่ผูกไว้
/newและ/resetจะรีเซ็ตเซสชัน ACP เดิมภายในตำแหน่งนั้น การผูกเธรดชั่วคราวสามารถเขียนทับการจำแนกเป้าหมายขณะที่ยังทำงานอยู่ spawnSessionsควบคุมการสร้าง/ผูกเธรดย่อยผ่าน--thread auto|here
ดูรายละเอียดลักษณะการทำงานของการผูกได้ที่ เอเจนต์ ACP
การแจ้งเตือนรีแอ็กชัน
โหมดการแจ้งเตือนรีแอ็กชันแยกตามกิลด์ (guilds.<id>.reactionNotifications):
offown(ค่าเริ่มต้น)allallowlist(ใช้guilds.<id>.users)
เหตุการณ์รีแอ็กชันจะถูกแปลงเป็นเหตุการณ์ระบบและแนบกับเซสชัน Discord ที่กำหนดเส้นทางแล้ว
รีแอ็กชันตอบรับ
ackReaction ส่งอีโมจิตอบรับขณะที่ OpenClaw ประมวลผลข้อความขาเข้า
ลำดับการจำแนกค่า:
channels.discord.accounts.<accountId>.ackReactionchannels.discord.ackReactionmessages.ackReaction- ใช้อีโมจิประจำตัวเอเจนต์เป็นค่าสำรอง (
agents.list[].identity.emojiหากไม่มีให้ใช้ "👀")
หมายเหตุ:
- Discord รองรับอีโมจิยูนิโคดหรือชื่ออีโมจิที่กำหนดเอง
- ใช้
""เพื่อปิดใช้รีแอ็กชันสำหรับช่องหรือบัญชี
ขอบเขต (messages.ackReactionScope):
ค่า: "all" (ข้อความส่วนตัว + กลุ่ม รวมถึงเหตุการณ์ห้องที่เกิดขึ้นโดยรอบ), "direct" (ข้อความส่วนตัวเท่านั้น), "group-all" (ทุกข้อความกลุ่มยกเว้นเหตุการณ์ห้องที่เกิดขึ้นโดยรอบ ไม่มีข้อความส่วนตัว), "group-mentions" (กลุ่มเมื่อมีการกล่าวถึงบอต โดย ไม่มีข้อความส่วนตัว และเป็นค่าเริ่มต้น), "off" / "none" (ปิดใช้งาน)
การเขียนการกำหนดค่า
การเขียนการกำหนดค่าที่เริ่มต้นจากช่องจะเปิดใช้งานโดยค่าเริ่มต้น ซึ่งมีผลต่อโฟลว์ /config set|unset (เมื่อเปิดใช้ฟีเจอร์คำสั่ง)
ปิดใช้งาน:
{channels: {discord: { configWrites: false,},},}พร็อกซี Gateway
กำหนดเส้นทางทราฟฟิก WebSocket ของเกตเวย์ Discord และการค้นหา REST ระหว่างเริ่มต้นระบบ (รหัสแอปพลิเคชัน + การจำแนกรายการอนุญาต) ผ่านพร็อกซี HTTP(S) ด้วย channels.discord.proxy
ต้องกำหนดการใช้พร็อกซีสำหรับ WebSocket ของเกตเวย์ Discord อย่างชัดเจน การเชื่อมต่อ WebSocket จะไม่สืบทอดตัวแปรสภาพแวดล้อมพร็อกซีโดยรอบจากกระบวนการ Gateway การค้นหา REST ระหว่างเริ่มต้นระบบจะใช้พร็อกซีนี้เมื่อกำหนดค่า channels.discord.proxy
{channels: {discord: { proxy: "http://proxy.example:8080",},},}การเขียนทับแยกตามบัญชี:
{channels: {discord: { accounts: { primary: { proxy: "http://proxy.example:8080", }, },},},}การรองรับ PluralKit
เปิดใช้การจำแนก PluralKit เพื่อจับคู่ข้อความที่ส่งผ่านพร็อกซีกับข้อมูลประจำตัวสมาชิกของระบบ:
{channels: {discord: { pluralkit: { enabled: true, token: "pk_live_...", // ไม่บังคับ; จำเป็นสำหรับระบบส่วนตัว },},},}หมายเหตุ:
- รายการอนุญาตสามารถใช้
pk:<memberId> - ชื่อที่แสดงของสมาชิกจะจับคู่ด้วยชื่อ/สลักเท่านั้นเมื่อ
channels.discord.dangerouslyAllowNameMatching: true - การค้นหาจะเรียกใช้ API ของ PluralKit ด้วย ID ข้อความต้นฉบับ
- หากการค้นหาล้มเหลว ข้อความที่ส่งผ่านพร็อกซีจะถือเป็นข้อความจากบอตและถูกละทิ้ง เว้นแต่
allowBotsจะอนุญาตให้ผ่าน
Outbound mention aliases
ใช้ mentionAliases เมื่อเอเจนต์ต้องระบุการกล่าวถึงขาออกแบบกำหนดแน่นอนสำหรับผู้ใช้ Discord ที่ทราบอยู่แล้ว คีย์คือชื่อเรียกที่ไม่มี @ นำหน้า ส่วนค่าคือ ID ผู้ใช้ Discord ชื่อเรียกที่ไม่รู้จัก, @everyone, @here และการกล่าวถึงภายในช่วงโค้ด Markdown จะคงเดิม
{channels: {discord: { mentionAliases: { SupportLead: "123456789012345678", }, accounts: { ops: { mentionAliases: { OpsLead: "234567890123456789", }, }, },},},}Presence configuration
การอัปเดตสถานะการออนไลน์จะมีผลเมื่อคุณกำหนดฟิลด์สถานะหรือกิจกรรม หรือเมื่อเปิดใช้สถานะการออนไลน์อัตโนมัติ
เฉพาะสถานะ:
{channels: {discord: { status: "idle",},},}กิจกรรม (สถานะแบบกำหนดเองเป็นประเภทกิจกรรมเริ่มต้นเมื่อกำหนด activity):
{channels: {discord: { activity: "Focus time", activityType: 4,},},}การสตรีม:
{channels: {discord: { activity: "Live coding", activityType: 1, activityUrl: "https://twitch.tv/openclaw",},},}ตารางประเภทกิจกรรม:
- 0: กำลังเล่น
- 1: กำลังสตรีม (ต้องมี
activityUrl; และactivityUrlต้องใช้ร่วมกับactivityType: 1) - 2: กำลังฟัง
- 3: กำลังรับชม
- 4: กำหนดเอง (ใช้ข้อความกิจกรรมเป็นค่าสถานะ; อีโมจิไม่บังคับ)
- 5: กำลังแข่งขัน
สถานะการออนไลน์อัตโนมัติ (สัญญาณสุขภาพของรันไทม์):
{channels: {discord: { autoPresence: { enabled: true, intervalMs: 30000, minUpdateIntervalMs: 15000, exhaustedText: "token exhausted", },},},}สถานะการออนไลน์อัตโนมัติจะจับคู่ความพร้อมใช้งานของรันไทม์กับสถานะ Discord: ปกติ => ออนไลน์, ประสิทธิภาพลดลงหรือไม่ทราบ => ไม่ได้ใช้งาน, โทเค็นหมดหรือไม่พร้อมใช้งาน => ห้ามรบกวน ค่าเริ่มต้น: intervalMs 30000, minUpdateIntervalMs 15000 (ต้องน้อยกว่าหรือเท่ากับ intervalMs) สามารถกำหนดข้อความทดแทนได้:
autoPresence.healthyTextautoPresence.degradedTextautoPresence.exhaustedText(รองรับตัวยึดตำแหน่ง{reason})
Approvals in Discord
Discord รองรับการจัดการการอนุมัติด้วยปุ่มในข้อความส่วนตัว และสามารถเลือกโพสต์คำขออนุมัติในช่องต้นทางได้
พาธการกำหนดค่า:
channels.discord.execApprovals.enabledchannels.discord.execApprovals.approvers(ไม่บังคับ; หากทำได้จะย้อนกลับไปใช้commands.ownerAllowFrom)channels.discord.execApprovals.target(dm|channel|both, ค่าเริ่มต้น:dm)agentFilter,sessionFilter,cleanupAfterResolve
Discord จะเปิดใช้การอนุมัติการดำเนินการแบบเนทีฟโดยอัตโนมัติเมื่อไม่ได้กำหนด enabled หรือกำหนดเป็น "auto" และสามารถระบุผู้อนุมัติได้อย่างน้อยหนึ่งราย ไม่ว่าจะจาก execApprovals.approvers หรือ commands.ownerAllowFrom Discord จะไม่อนุมานผู้อนุมัติการดำเนินการจาก allowFrom ของช่อง, dm.allowFrom แบบเดิม หรือ defaultTo ของข้อความส่วนตัว กำหนด enabled: false เพื่อปิดใช้ Discord ในฐานะไคลเอนต์การอนุมัติแบบเนทีฟอย่างชัดเจน
สำหรับคำสั่งกลุ่มที่ละเอียดอ่อนและจำกัดเฉพาะเจ้าของ เช่น /diagnostics และ /export-trajectory OpenClaw จะส่งคำขออนุมัติและผลลัพธ์สุดท้ายแบบส่วนตัว โดยจะลองใช้ข้อความส่วนตัวของ Discord ก่อนเมื่อเจ้าของที่เรียกใช้มีเส้นทางเจ้าของผ่าน Discord มิฉะนั้นจะย้อนกลับไปใช้เส้นทางเจ้าของแรกที่พร้อมใช้งานจาก commands.ownerAllowFrom เช่น Telegram
เมื่อ target เป็น channel หรือ both คำขออนุมัติจะปรากฏในช่อง เฉพาะผู้อนุมัติที่ระบุได้เท่านั้นที่สามารถใช้ปุ่มได้ ส่วนผู้ใช้อื่นจะได้รับการปฏิเสธที่มองเห็นได้เฉพาะตน คำขออนุมัติจะแสดงข้อความคำสั่งด้วย ดังนั้นควรเปิดใช้การส่งไปยังช่องเฉพาะในช่องที่เชื่อถือได้ หากไม่สามารถหา ID ช่องจากคีย์เซสชันได้ OpenClaw จะย้อนกลับไปส่งผ่านข้อความส่วนตัว
Discord จะแสดงปุ่มอนุมัติร่วมที่ช่องแชตอื่นใช้ อะแดปเตอร์ Discord แบบเนทีฟมีหน้าที่หลักในการกำหนดเส้นทางข้อความส่วนตัวไปยังผู้อนุมัติและกระจายไปยังช่อง เมื่อมีปุ่มเหล่านี้ ปุ่มจะเป็นประสบการณ์หลักสำหรับการอนุมัติ OpenClaw ควรแสดงคำสั่ง /approve แบบดำเนินการเองเฉพาะเมื่อผลลัพธ์ของเครื่องมือระบุว่าการอนุมัติผ่านแชตไม่พร้อมใช้งาน หรือการอนุมัติด้วยตนเองเป็นหนทางเดียว หากรันไทม์การอนุมัติแบบเนทีฟของ Discord ไม่ทำงาน OpenClaw จะยังแสดงข้อความแจ้ง /approve <id> <decision> ที่กำหนดผลลัพธ์แน่นอนภายในเครื่อง หากรันไทม์ทำงานอยู่แต่ไม่สามารถส่งการ์ดแบบเนทีฟไปยังเป้าหมายใดได้ OpenClaw จะส่งข้อความแจ้งสำรองในแชตเดียวกัน พร้อมคำสั่ง /approve ที่ตรงกับการอนุมัติที่รอดำเนินการทุกประการ
การยืนยันตัวตนของ Gateway และการประมวลผลการอนุมัติเป็นไปตามสัญญาไคลเอนต์ Gateway ร่วม (ID ที่ขึ้นต้นด้วย plugin: จะประมวลผลผ่าน plugin.approval.resolve; ID อื่นจะผ่าน exec.approval.resolve) โดยค่าเริ่มต้น การอนุมัติจะหมดอายุหลังจาก 30 นาที
เครื่องมือและด่านควบคุมการดำเนินการ
การดำเนินการกับข้อความ Discord ครอบคลุมการรับส่งข้อความ การดูแลช่อง การกลั่นกรอง สถานะการออนไลน์ และข้อมูลเมตา
ตัวอย่างหลัก:
- การรับส่งข้อความ:
sendMessage,readMessages,editMessage,deleteMessage,threadReply - ปฏิกิริยา:
react,reactions,emojiList - การกลั่นกรอง:
timeout,kick,ban - สถานะการออนไลน์:
setPresence
การดำเนินการ event-create รองรับพารามิเตอร์ image ที่ไม่บังคับ (URL หรือพาธไฟล์ภายในเครื่อง) สำหรับกำหนดภาพปกของกิจกรรมตามกำหนดการ
ด่านควบคุมการดำเนินการอยู่ภายใต้ channels.discord.actions.*
พฤติกรรมเริ่มต้นของด่านควบคุม:
| กลุ่มการดำเนินการ | ค่าเริ่มต้น |
|---|---|
| reactions, messages, threads, pins, polls, search, memberInfo, roleInfo, channelInfo, channels, voiceStatus, events, stickers, emojiUploads, stickerUploads, permissions | เปิดใช้ |
| roles | ปิดใช้ |
| moderation | ปิดใช้ |
| presence | ปิดใช้ |
UI คอมโพเนนต์ v2
OpenClaw ใช้คอมโพเนนต์ Discord v2 สำหรับการอนุมัติการดำเนินการและเครื่องหมายข้ามบริบท การดำเนินการกับข้อความ Discord ยังสามารถรับ components สำหรับ UI แบบกำหนดเองได้ด้วย (ขั้นสูง; ต้องสร้างเพย์โหลดคอมโพเนนต์ผ่านเครื่องมือ Discord) ขณะที่ embeds แบบเดิมยังคงใช้งานได้แต่ไม่แนะนำ
channels.discord.ui.components.accentColorกำหนดสีเน้นที่คอนเทนเนอร์คอมโพเนนต์ Discord ใช้ (เลขฐานสิบหก) แยกตามบัญชี:channels.discord.accounts.<id>.ui.components.accentColorchannels.discord.agentComponents.ttlMsควบคุมระยะเวลาที่คอลแบ็กของคอมโพเนนต์ Discord ที่ส่งไปแล้วยังคงลงทะเบียนอยู่ (ค่าเริ่มต้น1800000, สูงสุด86400000) แยกตามบัญชี:channels.discord.accounts.<id>.agentComponents.ttlMs- ระบบจะละเว้น
embedsเมื่อมีคอมโพเนนต์ v2 - การแสดงตัวอย่าง URL ธรรมดาจะถูกระงับโดยค่าเริ่มต้น กำหนด
suppressEmbeds: falseในการดำเนินการกับข้อความเมื่อต้องการให้ลิงก์ขาออกเพียงลิงก์เดียวแสดงตัวอย่างแบบขยาย
ตัวอย่าง:
{ channels: { discord: { ui: { components: { accentColor: "#5865F2", }, }, }, },}เสียง
Discord มีพื้นผิวเสียงสองแบบที่แตกต่างกัน ได้แก่ ช่องเสียง แบบเรียลไทม์ (การสนทนาต่อเนื่อง) และ ไฟล์แนบข้อความเสียง (รูปแบบแสดงตัวอย่างคลื่นเสียง) Gateway รองรับทั้งสองแบบ
ช่องเสียง
รายการตรวจสอบการตั้งค่า:
- เปิดใช้ Message Content Intent ใน Discord Developer Portal
- เปิดใช้ Server Members Intent เมื่อใช้รายการอนุญาตตามบทบาท/ผู้ใช้
- เชิญบอตโดยใช้ขอบเขต
botและapplications.commands - ให้สิทธิ์ Connect, Speak, Send Messages และ Read Message History ในช่องเสียงเป้าหมาย
- เปิดใช้คำสั่งแบบเนทีฟ (
commands.nativeหรือchannels.discord.commands.native) - กำหนดค่า
channels.discord.voice
ใช้ /vc join|leave|status เพื่อควบคุมเซสชัน คำสั่งนี้ใช้เอเจนต์เริ่มต้นของบัญชีและปฏิบัติตามกฎรายการอนุญาตและนโยบายกลุ่มเดียวกับคำสั่ง Discord อื่น
/vc join channel:<voice-channel-id>/vc status/vc leaveหากต้องการตรวจสอบสิทธิ์ที่มีผลจริงของบอตก่อนเข้าร่วม:
openclaw channels capabilities --channel discord --target channel:<voice-channel-id>ตัวอย่างการเข้าร่วมอัตโนมัติ:
{ channels: { discord: { voice: { enabled: true, model: "openai/gpt-5.6-sol", autoJoin: [ { guildId: "123456789012345678", channelId: "234567890123456789", }, ], allowedChannels: [ { guildId: "123456789012345678", channelId: "234567890123456789", }, ], daveEncryption: true, decryptionFailureTolerance: 24, connectTimeoutMs: 30000, reconnectGraceMs: 15000, realtime: { provider: "openai", model: "gpt-realtime-2.1", speakerVoice: "cedar", }, }, }, },}หมายเหตุ:
- เสียงของ Discord เป็นฟีเจอร์ที่ต้องเลือกเปิดใช้สำหรับการกำหนดค่าที่ใช้เฉพาะข้อความ ให้ตั้งค่า
channels.discord.voice.enabled=true(หรือคงบล็อกchannels.discord.voiceที่มีอยู่ไว้) เพื่อเปิดใช้คำสั่ง/vc, รันไทม์เสียง และเจตนาของ GatewayGuildVoiceStatesส่วนchannels.discord.intents.voiceStatesสามารถเขียนทับการสมัครรับเจตนานี้อย่างชัดเจนได้ หากไม่ตั้งค่า ระบบจะทำตามสถานะการเปิดใช้เสียงที่มีผลจริง voice.modeควบคุมเส้นทางการสนทนา ค่าเริ่มต้นคือagent-proxy: ส่วนหน้าสำหรับเสียงแบบเรียลไทม์จะจัดการจังหวะผลัดการพูด การขัดจังหวะ และการเล่นเสียง มอบหมายงานที่มีสาระให้เอเจนต์ OpenClaw ที่ถูกกำหนดเส้นทางผ่านopenclaw_agent_consultและปฏิบัติต่อผลลัพธ์เสมือนเป็นพรอมต์ Discord ที่ผู้พูดคนนั้นพิมพ์เข้ามา ส่วนstt-ttsจะคงโฟลว์แบบชุดเดิมที่ใช้ STT ร่วมกับ TTS และbidiช่วยให้โมเดลเรียลไทม์สนทนาได้โดยตรง พร้อมเปิดให้ใช้openclaw_agent_consultเป็นสมองของ OpenClawvoice.agentSessionควบคุมว่าการสนทนา OpenClaw ใดจะรับผลัดการพูดด้วยเสียง หากไม่ตั้งค่า จะใช้เซสชันของช่องเสียงเอง หรือตั้งค่าเป็น{ mode: "target", target: "channel:<text-channel-id>" }เพื่อให้ช่องเสียงทำหน้าที่เป็นส่วนขยายไมโครโฟน/ลำโพงของเซสชันช่องข้อความ Discord ที่มีอยู่ เช่น#maintainersvoice.modelเขียนทับสมองเอเจนต์ OpenClaw สำหรับการตอบกลับด้วยเสียงใน Discord และการปรึกษาแบบเรียลไทม์ หากไม่ตั้งค่า จะสืบทอดโมเดลเอเจนต์ที่ถูกกำหนดเส้นทาง ค่านี้แยกจากvoice.realtime.modelvoice.followUsersช่วยให้บอตเข้าร่วม ย้าย และออกจากเสียง Discord ตามผู้ใช้ที่เลือก โปรดดู ติดตามผู้ใช้ในเสียงagent-proxyกำหนดเส้นทางเสียงพูดผ่านdiscord-voiceซึ่งยังคงการอนุญาตของเจ้าของ/เครื่องมือตามปกติสำหรับผู้พูดและเซสชันเป้าหมาย แต่ซ่อนเครื่องมือttsของเอเจนต์ เนื่องจากเสียง Discord เป็นผู้ควบคุมการเล่น ตามค่าเริ่มต้นagent-proxyให้สิทธิ์เข้าถึงเครื่องมือแบบเต็มเทียบเท่าเจ้าของแก่การปรึกษาสำหรับผู้พูดที่เป็นเจ้าของ (voice.realtime.toolPolicy: "owner") และให้ความสำคัญอย่างยิ่งกับการปรึกษาเอเจนต์ OpenClaw ก่อนตอบคำถามที่มีสาระ (voice.realtime.consultPolicy: "always") ในโหมดalwaysเริ่มต้นนี้ ชั้นเรียลไทม์จะไม่พูดข้อความถ่วงเวลาโดยอัตโนมัติก่อนคำตอบจากการปรึกษา แต่จะจับและถอดเสียงคำพูด จากนั้นจึงพูดคำตอบของ OpenClaw ที่ถูกกำหนดเส้นทาง หากคำตอบจากการปรึกษาแบบบังคับหลายรายการเสร็จสิ้นขณะที่ Discord ยังเล่นคำตอบแรกอยู่ คำตอบแบบใช้ข้อความตรงเป็นคำพูดรายการหลังจะถูกเข้าคิวจนกว่าการเล่นจะว่าง แทนที่จะเขียนทับเสียงพูดกลางประโยค- ในโหมด
stt-ttsระบบ STT ใช้tools.media.audioและvoice.modelไม่มีผลต่อการถอดเสียง - ในโหมดเรียลไทม์
voice.realtime.provider,voice.realtime.modelและvoice.realtime.speakerVoiceใช้กำหนดค่าเซสชันเสียงเรียลไทม์ สำหรับ OpenAI Realtime 2.1 ร่วมกับสมอง Codex ให้ใช้voice.realtime.model: "gpt-realtime-2.1"และvoice.model: "openai/gpt-5.6-sol" - โดยค่าเริ่มต้น โหมดเสียงเรียลไทม์จะรวมไฟล์โปรไฟล์ขนาดเล็ก
IDENTITY.md,USER.mdและSOUL.mdไว้ในคำสั่งของผู้ให้บริการเรียลไทม์ เพื่อให้ผลัดการพูดโดยตรงแบบรวดเร็วยังคงอัตลักษณ์ การยึดโยงกับผู้ใช้ และบุคลิกเดียวกับเอเจนต์ OpenClaw ที่ถูกกำหนดเส้นทาง ตั้งค่าvoice.realtime.bootstrapContextFilesเป็นชุดย่อยเพื่อปรับแต่ง หรือเป็น[]เพื่อปิดใช้ รองรับเฉพาะไฟล์โปรไฟล์เหล่านี้เท่านั้น ส่วนAGENTS.mdยังคงอยู่ในบริบทเอเจนต์ตามปกติ บริบทโปรไฟล์ที่แทรกเข้ามาไม่สามารถใช้แทนopenclaw_agent_consultสำหรับงานในพื้นที่ทำงาน ข้อเท็จจริงปัจจุบัน การค้นหาหน่วยความจำ หรือการดำเนินการที่อาศัยเครื่องมือได้ - ในโหมดเรียลไทม์
agent-proxyของ OpenAI ให้ตั้งค่าvoice.realtime.requireWakeName: trueเพื่อให้เสียงเรียลไทม์ของ Discord เงียบอยู่จนกว่าข้อความถอดเสียงจะเริ่มต้นหรือลงท้ายด้วยชื่อปลุก ชื่อปลุกที่กำหนดค่าต้องมีหนึ่งหรือสองคำ หากไม่ได้ตั้งค่าvoice.realtime.wakeNamesOpenClaw จะใช้nameของเอเจนต์ที่ถูกกำหนดเส้นทางร่วมกับOpenClawและหากไม่มีจะใช้รหัสเอเจนต์ร่วมกับOpenClawการคัดกรองด้วยชื่อปลุกจะปิดการตอบกลับอัตโนมัติของผู้ให้บริการเรียลไทม์ กำหนดเส้นทางผลัดการพูดที่ยอมรับผ่านเส้นทางการปรึกษาเอเจนต์ OpenClaw และกล่าวตอบรับสั้น ๆ เมื่อระบบจดจำชื่อปลุกที่อยู่ต้นข้อความจากการถอดเสียงบางส่วนได้ ก่อนข้อความถอดเสียงสุดท้ายจะมาถึง - ผู้ให้บริการเรียลไทม์ของ OpenAI รองรับชื่อเหตุการณ์ Realtime 2 ปัจจุบันและนามแฝงแบบเดิมที่เข้ากันได้กับ Codex สำหรับเหตุการณ์เสียงเอาต์พุตและข้อความถอดเสียง ดังนั้นสแนปช็อตผู้ให้บริการที่เข้ากันได้จึงเปลี่ยนแปลงคลาดเคลื่อนได้โดยไม่ทำให้เสียงของผู้ช่วยสูญหาย
voice.realtime.bargeInควบคุมว่าเหตุการณ์เริ่มพูดของผู้พูดใน Discord จะขัดจังหวะการเล่นเสียงเรียลไทม์ที่กำลังทำงานอยู่หรือไม่ หากไม่ตั้งค่า ระบบจะทำตามการตั้งค่าการขัดจังหวะด้วยเสียงอินพุตของผู้ให้บริการเรียลไทม์voice.realtime.minBargeInAudioEndMsควบคุมระยะเวลาขั้นต่ำของการเล่นเสียงผู้ช่วย ก่อนที่การขัดจังหวะแบบเรียลไทม์ของ OpenAI จะตัดเสียง ค่าเริ่มต้น:250ตั้งค่าเป็น0เพื่อขัดจังหวะทันทีในห้องที่มีเสียงสะท้อนต่ำ หรือเพิ่มค่าในสภาพแวดล้อมที่ใช้ลำโพงและมีเสียงสะท้อนมากvoice.ttsเขียนทับmessages.ttsเฉพาะสำหรับการเล่นเสียงในโหมดstt-ttsส่วนโหมดเรียลไทม์จะใช้voice.realtime.speakerVoiceแทน สำหรับเสียง OpenAI ที่ใช้เล่นใน Discord ให้ตั้งค่าvoice.tts.provider: "openai"และเลือกเสียงแปลงข้อความเป็นคำพูดภายใต้voice.tts.providers.openai.speakerVoiceโดยcedarเป็นตัวเลือกที่ให้โทนเสียงผู้ชายได้ดีบนโมเดล TTS ของ OpenAI ปัจจุบัน- การเขียนทับ
systemPromptของ Discord รายช่องจะมีผลกับผลัดการพูดจากข้อความถอดเสียงในช่องเสียงนั้น - ผลัดการพูดจากข้อความถอดเสียงจะกำหนดสถานะเจ้าของจาก
allowFromของ Discord (หรือdm.allowFrom) สำหรับคำสั่งและการดำเนินการในช่องที่จำกัดเฉพาะเจ้าของ การมองเห็นเครื่องมือของเอเจนต์จะเป็นไปตามนโยบายเครื่องมือที่กำหนดค่าสำหรับเซสชันที่ถูกกำหนดเส้นทาง - หาก
voice.autoJoinมีหลายรายการสำหรับกิลด์เดียวกัน OpenClaw จะเข้าร่วมช่องสุดท้ายที่กำหนดค่าไว้สำหรับกิลด์นั้น voice.allowedChannelsคือรายการอนุญาตสำหรับช่องที่พำนักซึ่งเป็นตัวเลือก หากไม่ตั้งค่า จะอนุญาตให้/vc joinเข้าสู่ช่องเสียง Discord ใด ๆ ที่ได้รับอนุญาต เมื่อตั้งค่า/vc join, การเข้าร่วมอัตโนมัติเมื่อเริ่มต้น และการย้ายสถานะเสียงของบอต จะถูกจำกัดไว้เฉพาะรายการ{ guildId, channelId }ที่ระบุ ตั้งค่าเป็นอาร์เรย์ว่างเพื่อปฏิเสธการเข้าร่วมเสียง Discord ทั้งหมด หาก Discord ย้ายบอตออกนอกรายการอนุญาต OpenClaw จะออกจากช่องนั้นและกลับเข้าร่วมเป้าหมายการเข้าร่วมอัตโนมัติที่กำหนดค่าไว้เมื่อมีเป้าหมายดังกล่าวvoice.daveEncryptionและvoice.decryptionFailureToleranceจะถูกส่งต่อไปยังตัวเลือกการเข้าร่วมของ@discordjs/voiceโดยค่าเริ่มต้นของต้นทางคือdaveEncryption=trueและdecryptionFailureTolerance=24- OpenClaw ใช้โคเดก
libopus-wasmที่รวมมาให้สำหรับการรับเสียง Discord และการเล่น PCM ดิบแบบเรียลไทม์ โดยมาพร้อมบิลด์ WebAssembly ของ libopus ที่ตรึงเวอร์ชันไว้ และไม่ต้องใช้ส่วนเสริม opus แบบเนทีฟ voice.connectTimeoutMsควบคุมระยะเวลารอ Ready เริ่มต้นของ@discordjs/voiceสำหรับความพยายาม/vc joinและการเข้าร่วมอัตโนมัติ ค่าเริ่มต้น:30000voice.reconnectGraceMsควบคุมระยะเวลาที่ OpenClaw รอให้เซสชันเสียงที่ตัดการเชื่อมต่อเริ่มเชื่อมต่อใหม่ก่อนทำลายเซสชัน ค่าเริ่มต้น:15000- ในโหมด
stt-ttsการเล่นเสียงจะไม่หยุดเพียงเพราะผู้ใช้อื่นเริ่มพูด เพื่อหลีกเลี่ยงวงจรป้อนกลับ OpenClaw จะละเว้นการจับเสียงใหม่ขณะ TTS กำลังเล่น ให้พูดหลังจากเล่นเสร็จสำหรับผลัดถัดไป โหมดเรียลไทม์จะส่งต่อการเริ่มพูดของผู้พูดเป็นสัญญาณขัดจังหวะไปยังผู้ให้บริการเรียลไทม์ - ในโหมดเรียลไทม์ เสียงสะท้อนจากลำโพงที่เข้าสู่ไมโครโฟนซึ่งเปิดอยู่ อาจดูเหมือนการขัดจังหวะและหยุดการเล่นเสียง สำหรับห้อง Discord ที่มีเสียงสะท้อนมาก ให้ตั้งค่า
voice.realtime.providers.openai.interruptResponseOnInputAudio: falseเพื่อไม่ให้ OpenAI ขัดจังหวะอัตโนมัติเมื่อมีเสียงอินพุต เพิ่มvoice.realtime.bargeIn: trueหากยังต้องการให้เหตุการณ์เริ่มพูดของผู้พูดใน Discord ขัดจังหวะการเล่นที่กำลังทำงานอยู่ บริดจ์เรียลไทม์ของ OpenAI จะละเว้นการตัดการเล่นที่สั้นกว่าvoice.realtime.minBargeInAudioEndMsโดยถือว่าน่าจะเป็นเสียงสะท้อน/สัญญาณรบกวน และบันทึกว่าได้ข้ามเหตุการณ์นั้น แทนที่จะล้างการเล่นของ Discord voice.captureSilenceGraceMsควบคุมระยะเวลาที่ OpenClaw รอหลังจาก Discord รายงานว่าผู้พูดหยุดพูด ก่อนสรุปเซกเมนต์เสียงนั้นเพื่อส่งให้ STT ค่าเริ่มต้น:2000ให้เพิ่มค่านี้หาก Discord แบ่งช่วงหยุดปกติออกเป็นข้อความถอดเสียงบางส่วนที่ขาดเป็นช่วง ๆ- เมื่อเลือก ElevenLabs เป็นผู้ให้บริการ TTS การเล่นเสียง Discord จะใช้ TTS แบบสตรีมและเริ่มเล่นจากสตรีมการตอบกลับของผู้ให้บริการ ผู้ให้บริการที่ไม่รองรับการสตรีมจะย้อนกลับไปใช้เส้นทางไฟล์ชั่วคราวที่สังเคราะห์ขึ้น
- OpenClaw เฝ้าดูความล้มเหลวในการถอดรหัสของเสียงที่รับ และกู้คืนอัตโนมัติโดยออกจากแล้วกลับเข้าร่วมช่องเสียงหลังเกิดความล้มเหลวซ้ำ ๆ ภายในช่วงเวลาสั้น
- หากหลังอัปเดต บันทึกการรับแสดง
DecryptionFailed(UnencryptedWhenPassthroughDisabled)ซ้ำ ๆ ให้รวบรวมรายงานการขึ้นต่อกันและบันทึก บรรทัด@discordjs/voiceที่รวมมาให้มีการแก้ไขปัญหาการเติมข้อมูลจาก PR #11449 ของ discord.js ต้นทาง ซึ่งปิดปัญหา #11419 ของ discord.js แล้ว - เหตุการณ์การรับ
The operation was abortedเป็นสิ่งที่คาดไว้เมื่อ OpenClaw สรุปเซกเมนต์เสียงของผู้พูดที่จับไว้ เหตุการณ์เหล่านี้เป็นข้อมูลวินิจฉัยแบบละเอียด ไม่ใช่คำเตือน - บันทึกเสียง Discord แบบละเอียดจะมีตัวอย่างข้อความถอดเสียง STT หนึ่งบรรทัดที่จำกัดความยาวสำหรับแต่ละเซกเมนต์ของผู้พูดที่ยอมรับ เพื่อให้การแก้จุดบกพร่องแสดงทั้งฝั่งผู้ใช้และฝั่งคำตอบของเอเจนต์โดยไม่เทข้อความถอดเสียงที่ไม่จำกัดความยาว
- ในโหมด
agent-proxyการย้อนกลับไปใช้การปรึกษาแบบบังคับจะข้ามส่วนข้อความถอดเสียงที่น่าจะไม่สมบูรณ์ เช่น ข้อความที่ลงท้ายด้วย...หรือคำเชื่อมท้ายอย่าง "และ" รวมถึงคำปิดท้ายที่เห็นชัดว่าไม่ต้องดำเนินการ เช่น "เดี๋ยวกลับมา" หรือ "ลาก่อน" บันทึกจะแสดงforced agent consult skipped reason=...เมื่อกลไกนี้ป้องกันคำตอบเก่าที่ค้างอยู่ในคิว
ติดตามผู้ใช้ในเสียง
ใช้ voice.followUsers เมื่อต้องการให้บอตเสียง Discord อยู่กับผู้ใช้ Discord ที่รู้จักตั้งแต่หนึ่งคนขึ้นไป แทนการเข้าร่วมช่องคงที่เมื่อเริ่มต้นหรือรอ /vc join
{ channels: { discord: { voice: { enabled: true, followUsersEnabled: true, followUsers: ["discord:123456789012345678"], allowedChannels: [ { guildId: "123456789012345678", channelId: "234567890123456789", }, ], }, }, },}ลักษณะการทำงาน:
followUsersยอมรับรหัสผู้ใช้ Discord แบบดิบและค่าdiscord:<id>OpenClaw จะปรับทั้งสองรูปแบบให้เป็นมาตรฐานก่อนจับคู่เหตุการณ์สถานะเสียงfollowUsersEnabledมีค่าเริ่มต้นเป็นtrueเมื่อกำหนดค่าfollowUsersตั้งค่าเป็นfalseเพื่อเก็บรายการที่บันทึกไว้แต่หยุดการติดตามเสียงอัตโนมัติ- เมื่อผู้ใช้ที่ติดตามเข้าร่วมช่องเสียงที่อนุญาต OpenClaw จะเข้าร่วมช่องนั้น เมื่อผู้ใช้ย้าย OpenClaw จะย้ายตาม และเมื่อผู้ใช้ที่กำลังติดตามตัดการเชื่อมต่อ OpenClaw จะออก
- หากมีผู้ใช้ที่ติดตามหลายคนอยู่ในกิลด์เดียวกัน และผู้ใช้ที่กำลังติดตามออก OpenClaw จะย้ายไปยังช่องของผู้ใช้ที่ติดตามและกำลังถูกตรวจสอบคนอื่นก่อนออกจากกิลด์ หากผู้ใช้ที่ติดตามหลายคนย้ายพร้อมกัน เหตุการณ์สถานะเสียงที่สังเกตเห็นล่าสุดจะมีผล
allowedChannelsยังคงมีผล ผู้ใช้ที่ติดตามซึ่งอยู่ในช่องที่ไม่อนุญาตจะถูกละเว้น และเซสชันที่การติดตามเป็นเจ้าของจะย้ายไปยังผู้ใช้ที่ติดตามคนอื่นหรือออก- OpenClaw จะกระทบยอดเหตุการณ์สถานะเสียงที่พลาดไปเมื่อเริ่มต้นและตามช่วงเวลาที่จำกัดไว้ การกระทบยอดจะสุ่มตรวจสอบกิลด์ที่กำหนดค่าและจำกัดจำนวนการค้นหาผ่าน REST ต่อรอบ ดังนั้นรายการ
followUsersที่มีขนาดใหญ่มากอาจต้องใช้มากกว่าหนึ่งช่วงเวลาจึงจะเข้าสู่สถานะสอดคล้องกัน - หาก Discord หรือผู้ดูแลระบบย้ายบอตขณะที่กำลังติดตามผู้ใช้ OpenClaw จะสร้างเซสชันเสียงใหม่และคงความเป็นเจ้าของโดยการติดตามไว้เมื่อปลายทางได้รับอนุญาต หากบอตถูกย้ายออกนอก
allowedChannelsOpenClaw จะออกและกลับเข้าร่วมเป้าหมายที่กำหนดค่าไว้เมื่อมีเป้าหมายดังกล่าว - การกู้คืนการรับ DAVE อาจออกจากและกลับเข้าร่วมช่องเดิมหลังจากถอดรหัสล้มเหลวซ้ำ ๆ เซสชันที่การติดตามเป็นเจ้าของจะคงความเป็นเจ้าของโดยการติดตามผ่านเส้นทางการกู้คืนนี้ ดังนั้นเมื่อผู้ใช้ที่ติดตามตัดการเชื่อมต่อในภายหลัง ระบบยังคงออกจากช่อง
เลือกระหว่างโหมดการเข้าร่วม:
- ใช้
followUsersสำหรับการตั้งค่าส่วนบุคคลหรือการตั้งค่าของผู้ควบคุม ซึ่งบอตควรอยู่ในเสียงโดยอัตโนมัติเมื่อคุณอยู่ - ใช้
autoJoinสำหรับบอตประจำห้องที่ควรอยู่แม้ไม่มีผู้ใช้ที่ติดตามอยู่ในเสียง - ใช้
/vc joinสำหรับการเข้าร่วมครั้งเดียวหรือห้องที่การปรากฏตัวด้วยเสียงอัตโนมัติอาจเป็นเรื่องไม่คาดคิด
โคเดกเสียง Discord:
- บันทึกการรับเสียงแสดง
discord voice: opus decoder: libopus-wasm - การเล่นแบบเรียลไทม์จะเข้ารหัส PCM สเตอริโอดิบ 48 kHz เป็น Opus ด้วยแพ็กเกจ
libopus-wasmที่รวมมาให้ชุดเดียวกัน ก่อนส่งแพ็กเก็ตให้@discordjs/voice - การเล่นจากไฟล์และสตรีมของผู้ให้บริการจะแปลงเป็น PCM สเตอริโอดิบ 48 kHz ด้วย ffmpeg จากนั้นใช้
libopus-wasmสำหรับสตรีมแพ็กเก็ต Opus ที่ส่งไปยัง Discord
ไปป์ไลน์ STT ร่วมกับ TTS:
- การบันทึกเสียง PCM ของ Discord จะถูกแปลงเป็นไฟล์ WAV ชั่วคราว
tools.media.audioจัดการ STT เช่นopenai/gpt-4o-mini-transcribe- ทรานสคริปต์จะถูกส่งผ่านทางเข้าข้อความและการกำหนดเส้นทางของ Discord ขณะที่ LLM สำหรับการตอบกลับทำงานภายใต้นโยบายเอาต์พุตเสียงที่ซ่อนเครื่องมือ
ttsของเอเจนต์และกำหนดให้ส่งคืนข้อความ เนื่องจากระบบเสียงของ Discord เป็นผู้ควบคุมการเล่น TTS ขั้นสุดท้าย - เมื่อตั้งค่า
voice.modelค่านี้จะแทนที่เฉพาะ LLM สำหรับการตอบกลับในรอบของช่องเสียงนี้ voice.ttsจะถูกรวมทับบนmessages.ttsโดยผู้ให้บริการที่รองรับการสตรีมจะส่งข้อมูลเข้าสู่เครื่องเล่นโดยตรง มิฉะนั้นไฟล์เสียงที่ได้จะถูกเล่นในช่องที่เข้าร่วมอยู่
ตัวอย่างเซสชันช่องเสียงแบบพร็อกซีเอเจนต์เริ่มต้น:
{ channels: { discord: { voice: { enabled: true, model: "openai/gpt-5.6-sol", followUsersEnabled: true, followUsers: ["123456789012345678"], realtime: { provider: "openai", model: "gpt-realtime-2.1", speakerVoice: "cedar", }, }, }, },}หากไม่มีบล็อก voice.agentSession ช่องเสียงแต่ละช่องจะมีเซสชัน OpenClaw ที่กำหนดเส้นทางไว้เป็นของตนเอง ตัวอย่างเช่น /vc join channel:234567890123456789 จะสื่อสารกับเซสชันของช่องเสียง Discord นั้น โมเดลแบบเรียลไทม์เป็นเพียงส่วนหน้าสำหรับเสียงเท่านั้น ส่วนคำขอที่มีเนื้อหาสาระจะถูกส่งต่อให้เอเจนต์ OpenClaw ที่กำหนดค่าไว้ หากโมเดลแบบเรียลไทม์สร้างทรานสคริปต์สุดท้ายโดยไม่เรียกใช้เครื่องมือปรึกษา OpenClaw จะบังคับให้มีการปรึกษาเป็นกลไกสำรอง เพื่อให้พฤติกรรมเริ่มต้นยังคงเหมือนการสนทนากับเอเจนต์
ตัวอย่าง STT ร่วมกับ TTS แบบเดิม:
{ channels: { discord: { voice: { enabled: true, mode: "stt-tts", model: "openai/gpt-5.4-mini", tts: { provider: "openai", providers: { openai: { model: "gpt-4o-mini-tts", speakerVoice: "cedar", }, }, }, }, }, },}ตัวอย่างการสื่อสารสองทิศทางแบบเรียลไทม์:
{ channels: { discord: { voice: { enabled: true, mode: "bidi", model: "openai/gpt-5.6-sol", realtime: { provider: "openai", model: "gpt-realtime-2.1", speakerVoice: "cedar", toolPolicy: "safe-read-only", consultPolicy: "always", }, }, }, },}เสียงในฐานะส่วนขยายของเซสชันช่อง Discord ที่มีอยู่:
{ channels: { discord: { voice: { enabled: true, mode: "agent-proxy", model: "openai/gpt-5.6-sol", agentSession: { mode: "target", target: "channel:123456789012345678", }, realtime: { provider: "openai", model: "gpt-realtime-2.1", speakerVoice: "cedar", }, }, }, },}ในโหมด agent-proxy บอตจะเข้าร่วมช่องเสียงที่กำหนดค่าไว้ แต่รอบการทำงานของเอเจนต์ OpenClaw จะใช้เซสชันและเอเจนต์ที่กำหนดเส้นทางตามปกติของช่องเป้าหมาย เซสชันเสียงแบบเรียลไทม์จะพูดผลลัพธ์ที่ส่งคืนกลับเข้าไปในช่องเสียง เอเจนต์ควบคุมยังคงใช้เครื่องมือรับส่งข้อความตามปกติได้ตามนโยบายเครื่องมือของตน รวมถึงการส่งข้อความ Discord แยกต่างหาก หากเป็นการดำเนินการที่เหมาะสม
ขณะที่การทำงาน OpenClaw ที่มอบหมายไว้กำลังดำเนินอยู่ ทรานสคริปต์เสียง Discord ใหม่จะถูกใช้เป็นคำสั่งควบคุมการทำงานแบบสด ก่อนที่จะเริ่มรอบการทำงานของเอเจนต์อีกครั้ง วลีอย่าง "สถานะ", "ยกเลิกอันนั้น", "ใช้การแก้ไขที่เล็กกว่า" หรือ "เมื่อเสร็จแล้วให้ตรวจสอบการทดสอบด้วย" จะถูกจำแนกเป็นอินพุตสำหรับสถานะ การยกเลิก การชี้นำ หรือการติดตามผลของเซสชันที่กำลังทำงาน ผลลัพธ์ของสถานะ การยกเลิก การชี้นำที่ยอมรับ และการติดตามผลจะถูกพูดกลับเข้าไปในช่องเสียง เพื่อให้ผู้เรียกทราบว่า OpenClaw จัดการคำขอนั้นแล้วหรือไม่
รูปแบบเป้าหมายที่มีประโยชน์:
target: "channel:123456789012345678"กำหนดเส้นทางผ่านเซสชันช่องข้อความ Discordtarget: "123456789012345678"จะถือว่าเป็นเป้าหมายช่องtarget: "dm:123456789012345678"หรือtarget: "user:123456789012345678"กำหนดเส้นทางผ่านเซสชันข้อความโดยตรงนั้น
ตัวอย่าง OpenAI Realtime สำหรับสภาพแวดล้อมที่มีเสียงสะท้อนมาก:
{ channels: { discord: { voice: { enabled: true, mode: "bidi", model: "openai/gpt-5.6-sol", realtime: { provider: "openai", model: "gpt-realtime-2.1", speakerVoice: "cedar", bargeIn: true, minBargeInAudioEndMs: 500, consultPolicy: "always", providers: { openai: { interruptResponseOnInputAudio: false, }, }, }, }, }, },}ใช้การตั้งค่านี้เมื่อโมเดลได้ยินเสียงที่ Discord เล่นกลับของตัวเองผ่านไมโครโฟนที่เปิดอยู่ แต่คุณยังต้องการขัดจังหวะด้วยการพูด OpenClaw จะป้องกันไม่ให้ OpenAI ขัดจังหวะโดยอัตโนมัติจากเสียงอินพุตดิบ ขณะที่ bargeIn: true ช่วยให้เหตุการณ์เริ่มพูดของผู้พูดใน Discord และเสียงของผู้พูดที่กำลังใช้งานอยู่สามารถยกเลิกการตอบกลับแบบเรียลไทม์ที่กำลังทำงาน ก่อนที่รอบเสียงที่บันทึกถัดไปจะไปถึง OpenAI สัญญาณแทรกเสียงที่เกิดเร็วมากและมีค่า audioEndMs ต่ำกว่า minBargeInAudioEndMs จะถือว่าอาจเป็นเสียงสะท้อนหรือสัญญาณรบกวนและถูกละเว้น เพื่อไม่ให้โมเดลหยุดเสียงตั้งแต่เฟรมแรกของการเล่น
บันทึกเสียงที่ควรพบ:
- เมื่อเข้าร่วม:
discord voice: joining ... voiceSession=... supervisorSession=... agentSessionMode=... voiceModel=... realtimeModel=... - เมื่อเริ่มทำงานแบบเรียลไทม์:
discord voice: realtime bridge starting ... autoRespond=false interruptResponse=false bargeIn=false minBargeInAudioEndMs=... - เมื่อมีเสียงจากผู้พูด:
discord voice: realtime speaker turn opened ...,discord voice: realtime input audio started ... outputAudioMs=... outputActive=...และdiscord voice: realtime speaker turn closed ... chunks=... discordBytes=... realtimeBytes=... interruptedPlayback=... - เมื่อข้ามคำพูดเก่าที่ค้างอยู่:
discord voice: realtime forced agent consult skipped reason=incomplete-transcript ...หรือreason=non-actionable-closing ... - เมื่อการตอบกลับแบบเรียลไทม์เสร็จสิ้น:
discord voice: realtime audio playback finishing reason=response.done ... audioMs=... chunks=... - เมื่อหยุดหรือรีเซ็ตการเล่น:
discord voice: realtime audio playback stopped reason=... audioMs=... elapsedMs=... chunks=... - เมื่อมีการปรึกษาแบบเรียลไทม์:
discord voice: realtime consult requested ... voiceSession=... supervisorSession=... question=... - เมื่อเอเจนต์ตอบ:
discord voice: agent turn answer ... - เมื่อจัดคิวคำพูดแบบตรงตามข้อความ:
discord voice: realtime exact speech queued ... queued=... outputAudioMs=... outputActive=...ตามด้วยdiscord voice: realtime exact speech dequeued reason=player-idle ... - เมื่อตรวจพบการแทรกเสียง:
discord voice: realtime barge-in detected source=speaker-start ...หรือdiscord voice: realtime barge-in detected source=active-speaker-audio ...ตามด้วยdiscord voice: realtime barge-in requested reason=... outputAudioMs=... outputActive=... - เมื่อขัดจังหวะแบบเรียลไทม์:
discord voice: realtime model interrupt requested client:response.cancel reason=barge-inตามด้วยdiscord voice: realtime model audio truncated client:conversation.item.truncate reason=barge-in audioEndMs=...หรือdiscord voice: realtime model interrupt confirmed server:response.done status=cancelled ... - เมื่อละเว้นเสียงสะท้อนหรือสัญญาณรบกวน:
discord voice: realtime model interrupt ignored client:conversation.item.truncate.skipped reason=barge-in audioEndMs=0 minAudioEndMs=250 - เมื่อปิดใช้การแทรกเสียง:
discord voice: realtime capture ignored during playback (barge-in disabled) ... - เมื่อไม่มีการเล่นเสียง:
discord voice: realtime barge-in ignored reason=... outputActive=false ... playbackChunks=0
หากต้องการดีบักเสียงที่ถูกตัด ให้อ่านบันทึกเสียงแบบเรียลไทม์ตามลำดับเวลา:
realtime audio playback startedหมายความว่า Discord เริ่มเล่นเสียงของผู้ช่วยแล้ว บริดจ์จะเริ่มนับส่วนข้อมูลเอาต์พุตของผู้ช่วย จำนวนไบต์ PCM ของ Discord จำนวนไบต์แบบเรียลไทม์ของผู้ให้บริการ และระยะเวลาเสียงที่สังเคราะห์ขึ้นนับจากจุดนี้realtime speaker turn openedระบุว่าผู้พูดใน Discord เริ่มทำงาน หากกำลังเล่นเสียงอยู่แล้วและเปิดใช้bargeInเหตุการณ์นี้อาจตามด้วยbarge-in detected source=speaker-startrealtime input audio startedระบุเฟรมเสียงจริงเฟรมแรกที่ได้รับในรอบการพูดนั้น หากตรงนี้มีoutputActive=trueหรือoutputAudioMsไม่เป็นศูนย์ แสดงว่าไมโครโฟนกำลังส่งอินพุตขณะที่เสียงของผู้ช่วยยังคงเล่นอยู่barge-in detected source=active-speaker-audioหมายความว่า OpenClaw ตรวจพบเสียงสดจากผู้พูดขณะที่เสียงของผู้ช่วยกำลังเล่นอยู่ ข้อมูลนี้ช่วยแยกแยะการขัดจังหวะจริงออกจากเหตุการณ์เริ่มพูดของ Discord ที่ไม่มีเสียงที่ใช้งานได้barge-in requested reason=...หมายความว่า OpenClaw ขอให้ผู้ให้บริการแบบเรียลไทม์ยกเลิกหรือตัดการตอบกลับที่กำลังทำงาน โดยมีoutputAudioMs,outputActiveและplaybackChunksเพื่อให้เห็นว่าเสียงของผู้ช่วยถูกเล่นจริงไปมากเพียงใดก่อนการขัดจังหวะrealtime audio playback stopped reason=...คือจุดรีเซ็ตการเล่นเสียงภายใน Discord เหตุผลจะระบุว่าใครหยุดการเล่น ได้แก่barge-in,player-idle,provider-clear-audio,forced-agent-consult,stream-closeหรือsession-closerealtime speaker turn closedสรุปรอบอินพุตที่บันทึกไว้ หากchunks=0หรือhasAudio=falseหมายความว่ารอบการพูดเปิดขึ้น แต่ไม่มีเสียงที่ใช้งานได้ไปถึงบริดจ์แบบเรียลไทม์ หากinterruptedPlayback=trueหมายความว่ารอบอินพุตนั้นทับซ้อนกับเอาต์พุตของผู้ช่วยและเรียกใช้ตรรกะการแทรกเสียง
ฟิลด์ที่มีประโยชน์:
outputAudioMs: ระยะเวลาเสียงของผู้ช่วยที่ผู้ให้บริการแบบเรียลไทม์สร้างขึ้นก่อนบรรทัดบันทึกนั้นaudioMs: ระยะเวลาเสียงของผู้ช่วยที่ OpenClaw นับได้ก่อนหยุดเล่นelapsedMs: เวลาตามนาฬิการะหว่างการเปิดและปิดสตรีมการเล่นหรือรอบการพูดdiscordBytes: จำนวนไบต์ PCM สเตอริโอ 48 kHz ที่ส่งไปยังหรือรับมาจากระบบเสียง DiscordrealtimeBytes: จำนวนไบต์ PCM ในรูปแบบของผู้ให้บริการที่ส่งไปยังหรือรับมาจากผู้ให้บริการแบบเรียลไทม์playbackChunks: ส่วนข้อมูลเสียงของผู้ช่วยที่ส่งต่อไปยัง Discord สำหรับการตอบกลับที่กำลังทำงานsinceLastAudioMs: ช่วงเวลาระหว่างเฟรมเสียงล่าสุดของผู้พูดที่บันทึกได้กับการปิดรอบการพูด
รูปแบบที่พบบ่อย:
- เสียงถูกตัดทันทีโดยมี
source=active-speaker-audio, ค่าoutputAudioMsต่ำ และผู้ใช้คนเดิมอยู่ใกล้เคียง มักบ่งชี้ว่าเสียงสะท้อนจากลำโพงเข้าสู่ไมโครโฟน ให้เพิ่มvoice.realtime.minBargeInAudioEndMsลดระดับเสียงลำโพง ใช้หูฟัง หรือตั้งค่าvoice.realtime.providers.openai.interruptResponseOnInputAudio: false source=speaker-startตามด้วยspeaker turn closed ... hasAudio=falseหมายความว่า Discord รายงานว่าผู้พูดเริ่มพูด แต่ไม่มีเสียงไปถึง OpenClaw ซึ่งอาจเป็นเหตุการณ์เสียงชั่วคราวของ Discord พฤติกรรมของตัวกรองเสียงรบกวน หรือไคลเอนต์เปิดไมโครโฟนเพียงชั่วขณะaudio playback stopped reason=stream-closeโดยไม่มีการแทรกเสียงหรือprovider-clear-audioใกล้เคียง หมายความว่าสตรีมการเล่นเสียงภายใน Discord สิ้นสุดลงโดยไม่คาดคิด ให้ตรวจสอบบันทึกของผู้ให้บริการและเครื่องเล่น Discord ก่อนหน้านั้นcapture ignored during playback (barge-in disabled)หมายความว่า OpenClaw ละทิ้งอินพุตโดยเจตนาขณะที่เสียงของผู้ช่วยกำลังเล่นอยู่ เปิดใช้voice.realtime.bargeInหากต้องการให้เสียงพูดขัดจังหวะการเล่นbarge-in ignored ... outputActive=falseหมายความว่า Discord หรือ VAD ของผู้ให้บริการรายงานเสียงพูด แต่ OpenClaw ไม่มีการเล่นเสียงที่กำลังทำงานให้ขัดจังหวะ กรณีนี้ไม่ควรตัดเสียง
ข้อมูลประจำตัวจะถูกแยกแก้ไขตามแต่ละองค์ประกอบ ได้แก่ การรับรองความถูกต้องของเส้นทาง LLM สำหรับ voice.model, การรับรองความถูกต้องของ STT สำหรับ tools.media.audio, การรับรองความถูกต้องของ TTS สำหรับ messages.tts/voice.tts และการรับรองความถูกต้องของผู้ให้บริการแบบเรียลไทม์สำหรับ voice.realtime.providers หรือการกำหนดค่าการรับรองความถูกต้องตามปกติของผู้ให้บริการ
ข้อความเสียง
ข้อความเสียง Discord แสดงตัวอย่างรูปคลื่นและต้องใช้เสียง OGG/Opus OpenClaw สร้างรูปคลื่นโดยอัตโนมัติ แต่ต้องมี ffmpeg และ ffprobe บนโฮสต์ Gateway เพื่อตรวจสอบและแปลงไฟล์
- ระบุ เส้นทางไฟล์ภายในเครื่อง (URL จะถูกปฏิเสธ)
- ไม่ต้องระบุเนื้อหาข้อความ (Discord ปฏิเสธข้อความและข้อความเสียงที่อยู่ในเพย์โหลดเดียวกัน)
- รองรับรูปแบบเสียงทุกชนิด โดย OpenClaw จะแปลงเป็น OGG/Opus ตามความจำเป็น
message(action="send", channel="discord", target="channel:123", path="/path/to/audio.mp3", asVoice=true)การแก้ไขปัญหา
ใช้เจตนาที่ไม่ได้รับอนุญาต หรือบอตไม่เห็นข้อความในกิลด์
- เปิดใช้งาน Message Content Intent
- เปิดใช้งาน Server Members Intent เมื่อคุณต้องใช้การระบุผู้ใช้/สมาชิก
- รีสตาร์ต Gateway หลังจากเปลี่ยน intents
ข้อความในกิลด์ถูกบล็อกโดยไม่คาดคิด
- ตรวจสอบ
groupPolicy - ตรวจสอบรายการอนุญาตของกิลด์ภายใต้
channels.discord.guilds - หากมีแมป
channelsของกิลด์ จะอนุญาตเฉพาะช่องที่ระบุไว้เท่านั้น - ตรวจสอบลักษณะการทำงานของ
requireMentionและรูปแบบการกล่าวถึง
การตรวจสอบที่มีประโยชน์:
openclaw doctoropenclaw channels status --probeopenclaw logs --followตั้งค่าไม่ต้องกล่าวถึงแล้วแต่ยังถูกบล็อก
สาเหตุที่พบบ่อย:
groupPolicy="allowlist"โดยไม่มีรายการอนุญาตของกิลด์/ช่องที่ตรงกัน- กำหนดค่า
requireMentionผิดตำแหน่ง (ต้องอยู่ภายใต้channels.discord.guildsหรือรายการของช่อง) - ผู้ส่งถูกบล็อกโดยรายการอนุญาต
usersของกิลด์/ช่อง
รอบการทำงานของ Discord ใช้เวลานานหรือมีการตอบซ้ำ
บันทึกทั่วไป:
Slow listener detected ...stuck session: sessionKey=agent:...:discord:... state=processing ...
ตัวปรับแต่งคิว Gateway ของ Discord:
- บัญชีเดียว:
channels.discord.eventQueue.listenerTimeout - หลายบัญชี:
channels.discord.accounts.<accountId>.eventQueue.listenerTimeout - ค่านี้ควบคุมเฉพาะงานของตัวรับฟัง Gateway ของ Discord ไม่ใช่อายุการทำงานของรอบเอเจนต์
Discord ไม่ใช้การหมดเวลาที่ช่องเป็นเจ้าของกับรอบเอเจนต์ที่อยู่ในคิว ตัวรับฟังข้อความจะส่งต่องานทันที และงาน Discord ที่อยู่ในคิวจะรักษาลำดับของแต่ละเซสชันไว้จนกว่าวงจรชีวิตของเซสชัน/เครื่องมือ/รันไทม์จะเสร็จสมบูรณ์หรือยกเลิกงาน
{channels: {discord: { accounts: { default: { eventQueue: { listenerTimeout: 120000, }, }, },},},}คำเตือนการหมดเวลาขณะค้นหาข้อมูลเมตาของ Gateway
OpenClaw ดึงข้อมูลเมตา /gateway/bot ของ Discord ก่อนเชื่อมต่อ หากเกิดความล้มเหลวชั่วคราว ระบบจะย้อนกลับไปใช้ URL ของ Gateway เริ่มต้นของ Discord และจำกัดอัตราการบันทึกข้อความ
ตัวปรับแต่งการหมดเวลาของข้อมูลเมตา:
- บัญชีเดียว:
channels.discord.gatewayInfoTimeoutMs - หลายบัญชี:
channels.discord.accounts.<accountId>.gatewayInfoTimeoutMs - ค่าสำรองจากตัวแปรสภาพแวดล้อมเมื่อไม่ได้กำหนดค่าในไฟล์ตั้งค่า:
OPENCLAW_DISCORD_GATEWAY_INFO_TIMEOUT_MS - ค่าเริ่มต้น:
30000(30 วินาที), ค่าสูงสุด:120000
การรีสตาร์ตเมื่อเหตุการณ์ READY ของ Gateway หมดเวลา
OpenClaw รอเหตุการณ์ READY ของ Gateway จาก Discord ระหว่างการเริ่มต้นระบบและหลังการเชื่อมต่อรันไทม์ใหม่ การตั้งค่าแบบหลายบัญชีที่ทยอยเริ่มต้นอาจต้องใช้ช่วงเวลารอ READY ระหว่างเริ่มต้นที่นานกว่าค่าเริ่มต้น
ตัวปรับแต่งการหมดเวลา READY:
- การเริ่มต้นแบบบัญชีเดียว:
channels.discord.gatewayReadyTimeoutMs - การเริ่มต้นแบบหลายบัญชี:
channels.discord.accounts.<accountId>.gatewayReadyTimeoutMs - ค่าสำรองจากตัวแปรสภาพแวดล้อมระหว่างเริ่มต้นเมื่อไม่ได้กำหนดค่าในไฟล์ตั้งค่า:
OPENCLAW_DISCORD_READY_TIMEOUT_MS - ค่าเริ่มต้นระหว่างเริ่มต้น:
15000(15 วินาที), ค่าสูงสุด:120000 - รันไทม์แบบบัญชีเดียว:
channels.discord.gatewayRuntimeReadyTimeoutMs - รันไทม์แบบหลายบัญชี:
channels.discord.accounts.<accountId>.gatewayRuntimeReadyTimeoutMs - ค่าสำรองจากตัวแปรสภาพแวดล้อมของรันไทม์เมื่อไม่ได้กำหนดค่าในไฟล์ตั้งค่า:
OPENCLAW_DISCORD_RUNTIME_READY_TIMEOUT_MS - ค่าเริ่มต้นของรันไทม์:
30000(30 วินาที), ค่าสูงสุด:120000
ผลการตรวจสอบสิทธิ์ไม่ตรงกัน
การตรวจสอบสิทธิ์ของ channels status --probe ใช้ได้เฉพาะกับ ID ช่องที่เป็นตัวเลขเท่านั้น
หากคุณใช้คีย์แบบ slug การจับคู่ขณะรันไทม์ยังคงทำงานได้ แต่การตรวจสอบไม่สามารถยืนยันสิทธิ์ได้อย่างสมบูรณ์
ปัญหาข้อความส่วนตัวและการจับคู่
- ปิดใช้งานข้อความส่วนตัว:
channels.discord.dm.enabled=false - ปิดใช้งานนโยบายข้อความส่วนตัว:
channels.discord.dmPolicy="disabled"(แบบเดิม:channels.discord.dm.policy) - กำลังรอการอนุมัติการจับคู่ในโหมด
pairing
ลูประหว่างบอต
โดยค่าเริ่มต้น ระบบจะละเว้นข้อความที่บอตเป็นผู้ส่ง
หากคุณตั้งค่า channels.discord.allowBots=true ให้ใช้กฎการกล่าวถึงและรายการอนุญาตที่เข้มงวดเพื่อหลีกเลี่ยงการเกิดลูป
ควรใช้ channels.discord.allowBots="mentions" เพื่อยอมรับเฉพาะข้อความจากบอตที่กล่าวถึงบอตนี้เท่านั้น
OpenClaw ยังมาพร้อมกับ การป้องกันลูปของบอต ที่ใช้ร่วมกัน เมื่อใดก็ตามที่ allowBots อนุญาตให้ข้อความจากบอตเข้าสู่การส่งต่อ Discord จะแมปเหตุการณ์ขาเข้าเป็นข้อเท็จจริง (บัญชี, ช่อง, คู่บอต) และตัวป้องกันคู่แบบทั่วไปจะระงับคู่นั้นหลังจากเกินโควตาเหตุการณ์ที่กำหนด ตัวป้องกันนี้ช่วยหยุดลูปสองบอตที่ควบคุมไม่ได้ ซึ่งก่อนหน้านี้ต้องอาศัยการจำกัดอัตราของ Discord เพื่อหยุด และไม่ส่งผลต่อการติดตั้งใช้งานแบบบอตเดียวหรือการตอบกลับจากบอตเพียงครั้งเดียวที่ไม่เกินโควตา
การตั้งค่าเริ่มต้น (ทำงานเมื่อตั้งค่า allowBots):
maxEventsPerWindow: 20-- คู่บอตสามารถแลกเปลี่ยนข้อความได้ 20 ข้อความภายในกรอบเวลาแบบเลื่อนwindowSeconds: 60-- ความยาวของกรอบเวลาแบบเลื่อนcooldownSeconds: 60-- เมื่อใช้โควตาครบแล้ว ข้อความระหว่างบอตเพิ่มเติมทุกข้อความในทั้งสองทิศทางจะถูกทิ้งเป็นเวลาหนึ่งนาที
กำหนดค่าเริ่มต้นที่ใช้ร่วมกันเพียงครั้งเดียวภายใต้ channels.defaults.botLoopProtection แล้วเขียนทับสำหรับ Discord เมื่อเวิร์กโฟลว์ที่ถูกต้องต้องการโควตาเพิ่มขึ้น ลำดับความสำคัญคือ:
channels.discord.accounts.<account>.botLoopProtectionchannels.discord.botLoopProtectionchannels.defaults.botLoopProtection- ค่าเริ่มต้นในตัว
Discord ใช้คีย์ทั่วไป maxEventsPerWindow, windowSeconds และ cooldownSeconds
{channels: {defaults: { botLoopProtection: { maxEventsPerWindow: 20, windowSeconds: 60, cooldownSeconds: 60, },},discord: { // การเขียนทับสำหรับ Discord ทั้งหมดที่ไม่บังคับ บล็อกบัญชีจะเขียนทับแต่ละฟิลด์ // และรับช่วงฟิลด์ที่ละไว้จากที่นี่ botLoopProtection: { maxEventsPerWindow: 4, }, accounts: { alpha: { // Alpha รับฟังบอตอื่นเฉพาะเมื่อบอตเหล่านั้นกล่าวถึง Alpha allowBots: "mentions", }, bravo: { // Bravo รับฟังข้อความ Discord ทั้งหมดที่บอตเป็นผู้ส่ง allowBots: true, mentionAliases: { // อนุญาตให้ Bravo เขียนการกล่าวถึง Alpha ใน Discord ด้วย ID ผู้ใช้ที่กำหนดค่าไว้ Alpha: "ALPHA_DISCORD_USER_ID", }, botLoopProtection: { // อนุญาตได้สูงสุดห้าข้อความต่อนาทีก่อนระงับคู่นี้ maxEventsPerWindow: 5, windowSeconds: 60, cooldownSeconds: 90, }, }, },},},}เสียงพูดเป็นข้อความขาดหายพร้อมข้อผิดพลาด DecryptionFailed(...)
- อัปเดต OpenClaw ให้เป็นเวอร์ชันปัจจุบันเสมอ (
openclaw update) เพื่อให้มีตรรกะกู้คืนการรับเสียงของ Discord - ยืนยันว่า
channels.discord.voice.daveEncryption=true(ค่าเริ่มต้น) - เริ่มจาก
channels.discord.voice.decryptionFailureTolerance=24(ค่าเริ่มต้นของต้นทาง) และปรับเฉพาะเมื่อจำเป็น - เฝ้าดูบันทึกต่อไปนี้:
discord voice: DAVE decrypt failures detecteddiscord voice: repeated decrypt failures; attempting rejoin
- หากยังเกิดความล้มเหลวหลังจากเข้าร่วมใหม่โดยอัตโนมัติ ให้รวบรวมบันทึกและเปรียบเทียบกับประวัติการรับ DAVE ของต้นทางใน discord.js #11419 และ discord.js #11449
ข้อมูลอ้างอิงการกำหนดค่า
ข้อมูลอ้างอิงหลัก: ข้อมูลอ้างอิงการกำหนดค่า - Discord
ฟิลด์ Discord ที่สำคัญ
- การเริ่มต้น/การยืนยันตัวตน:
enabled,token,applicationId,accounts.*,allowBots - นโยบาย:
groupPolicy,dmPolicy,allowFrom,dm.*,guilds.*,guilds.*.channels.* - คำสั่ง:
commands.native,commands.useAccessGroups(ส่วนกลาง),configWrites,slashCommand.ephemeral - คิวเหตุการณ์:
eventQueue.listenerTimeout(โควตาเวลาของตัวรับฟัง, ค่าเริ่มต้น120000),eventQueue.maxQueueSize(ค่าเริ่มต้น10000),eventQueue.maxConcurrency(ค่าเริ่มต้น50) - Gateway:
proxy,gatewayInfoTimeoutMs,gatewayReadyTimeoutMs,gatewayRuntimeReadyTimeoutMs - การตอบกลับ/ประวัติ:
replyToMode,historyLimit,dmHistoryLimit,dms.*.historyLimit - การส่ง:
textChunkLimit(ค่าเริ่มต้น2000),maxLinesPerMessage(ค่าเริ่มต้น17) - การสตรีม:
streaming.mode,streaming.chunkMode,streaming.preview.*,streaming.progress.*,streaming.block.*(คีย์แบบแบนเดิมstreamMode,draftChunk,blockStreaming,blockStreamingCoalesce,chunkModeจะถูกย้ายไปยังstreaming.*โดยopenclaw doctor --fix) - สื่อ/การลองใหม่:
mediaMaxMb(จำกัดขนาดการอัปโหลดขาออกไปยัง Discord, ค่าเริ่มต้น100),retry - การดำเนินการ:
actions.* - สถานะการแสดงตัว:
activity,status,activityType,activityUrl,autoPresence.* - ส่วนติดต่อผู้ใช้:
ui.components.accentColor - คุณสมบัติ:
threadBindings,bindings[]ระดับบนสุด (type: "acp"),pluralkit,execApprovals,intents,agentComponents.enabled,agentComponents.ttlMs,heartbeat,responsePrefix
ความปลอดภัยและการดำเนินงาน
- จัดการโทเค็นของบอตเสมือนเป็นข้อมูลลับ (แนะนำให้ใช้
DISCORD_BOT_TOKENในสภาพแวดล้อมที่มีระบบกำกับดูแล) - ให้สิทธิ์ Discord เท่าที่จำเป็นเท่านั้น
- หากการปรับใช้/สถานะคำสั่งล้าสมัย ให้รีสตาร์ต Gateway และตรวจสอบอีกครั้งด้วย
openclaw channels status --probe
ที่เกี่ยวข้อง
จับคู่ผู้ใช้ Discord กับ Gateway
ลักษณะการทำงานของแชตกลุ่มและรายการอนุญาต
กำหนดเส้นทางข้อความขาเข้าไปยังเอเจนต์
แบบจำลองภัยคุกคามและการเสริมความมั่นคงปลอดภัย
แมปกิลด์และช่องกับเอเจนต์
ลักษณะการทำงานของคำสั่งแบบเนทีฟ