[Discord斜杠命令返回'Done.'而非富数据] - Discord Slash Command Returns 'Done.' Instead of Rich Data
OpenClaw最新版本中的回归问题:/status斜杠命令显示'Done.'文本,而不是显示预期的富嵌入数据响应。
🔍 症状
/status Discord 斜杠命令执行时不会抛出可见错误,但只返回纯文本"Done.“消息,而不是预期的富嵌入式数据。
CLI 执行示例
当命令被调用时,机器人以最小化输出响应:
User: /status
Bot: Done.
预期响应(之前的行为):
User: /status
Bot: [包含状态信息、模型信息、系统指标等的富嵌入式消息]
诊断指标
- 退出代码:
0(命令成功完成) - 控制台输出无错误日志
- 响应及时到达(未超时)
- 命令在文本频道环境下工作,但在私信环境下失败
- 机器人具有正确的
APPLICATION_COMMANDS权限范围
次要症状
- 交互确认可能显示为
“正在思考…",然后恢复为"Done.” - 响应缺少嵌入式格式、颜色或字段
- 消息上的时间戳显示正确的执行时间
- 后续命令继续正常工作
🧠 根因分析
“Done.“响应是 Discord.js 在交互响应未正确创建或在初始确认后未正确编辑时的默认回退消息。
技术故障序列
- 收到交互: Discord 向 OpenClaw 处理器发送
INTERACTION_CREATE事件 - 初始确认: OpenClaw 调用
interaction.reply()并以{ content: "Done." }作为默认回退 - 处理器执行: 实际的状态处理器开始处理数据
- 响应失败: 处理器尝试使用
interaction.editReply()或interaction.followUp() - 回调解析缺失: 响应由于以下原因从未到达后续方法:
- 处理器链中 async/await 未正确等待
- Promise 拒绝被静默吞没
- 交互对象引用变为过时
- 默认显示: Discord 渲染初始的 "Done." 确认
架构不一致
OpenClaw 的 Discord 适配器改变了交互延迟响应的处理方式:
之前(正常工作):
await interaction.reply({ embeds: [statusEmbed] });
之后(出现问题):
await interaction.deferReply(); // 隐式确认,显示 "Done."
// ... 异步处理 ...
await interaction.editReply({ embeds: [statusEmbed] }); // 静默失败
延迟模式假设后续编辑将成功完成。处理链中的任何异常都会导致 “Done.” 持续显示。
受影响的特定代码路径
src/adapters/discord/interaction-handler.ts:响应编辑周围缺少 try-catchsrc/commands/status/index.ts:处理器可能未正确等待数据获取src/providers/openclaw/status-service.ts:在某些环境中数据检索可能抛出异常
🛠️ 逐步修复
方法 1:确保同步响应(推荐)
修改状态命令处理器以直接响应,无需延迟:
// 之前(导致回归)
statusCommand: async (interaction) => {
await interaction.deferReply();
const status = await fetchStatusData();
await interaction.editReply({ embeds: [buildEmbed(status)] });
}
// 之后(正确)
statusCommand: async (interaction) => {
const status = await fetchStatusData();
await interaction.reply({ embeds: [buildEmbed(status)] });
}
方法 2:添加健壮的错误处理
使用全面的错误处理包装延迟响应流程:
statusCommand: async (interaction) => {
await interaction.deferReply({ ephemeral: false }).catch(err => {
console.error('延迟失败:', err);
throw err; // 传播以防止静默失败
});
try {
const status = await fetchStatusData();
const embed = buildEmbed(status);
await interaction.editReply({ embeds: [embed] }).catch(err => {
console.error('editReply 失败:', err);
await interaction.reply({ embeds: [embed] }); // 回退
});
} catch (error) {
console.error('状态获取失败:', error);
await interaction.editReply({
content: '⚠️ 获取状态信息失败。',
embeds: []
}).catch(() => {
await interaction.reply('⚠️ 获取状态信息失败。');
});
}
}
方法 3:验证适配器配置
确保 Discord 适配器在 OpenClaw 配置中正确设置:
// openclaw.config.ts
export default {
adapters: {
discord: {
intents: ['Guilds', 'GuildMessages', 'DirectMessages'],
// 显式设置响应模式
useLegacyContextMenus: false,
respondOnDefer: false // 禁用隐式 "Done." 响应
}
}
}
方法 4:检查斜杠命令注册
强制重新注册斜杠命令以确保正确的权限:
# 删除现有命令
npx openclaw discord commands delete status --guild YOUR_GUILD_ID
# 清除全局缓存
npx openclaw discord cache clear
# 重新注册
npx openclaw discord commands register
# 验证注册
npx openclaw discord commands list
🧪 验证
测试命令
1. 验证命令注册:
npx openclaw discord commands list --verbose
# 预期:/status 命令以正确的描述和选项出现
2. 在公共频道中测试:
# 在文本频道(非私信)中
/status
# 预期:富嵌入包含所有用户可见的状态数据
3. 在私信环境中测试:
# 在机器人私信中
/status
# 预期:富嵌入包含状态数据
# 如果仍然显示 "Done.":问题在私信特定处理中
4. 启用调试日志:
# 设置环境变量
export LOG_LEVEL=debug
export DEBUG=openclaw:discord:*
# 重启 OpenClaw
npx openclaw start
# 执行 /status 并观察日志
# 查找:"interaction.reply"、"interaction.deferReply"、"interaction.editReply"
预期日志输出(修复后状态)
[DEBUG] openclaw:discord:interaction - 收到 /status 的 INTERACTION_CREATE
[DEBUG] openclaw:discord:interaction - 调用状态处理器
[DEBUG] openclaw:discord:interaction - 从提供者获取状态数据
[DEBUG] openclaw:discord:interaction - 使用 5 个字段构建嵌入
[INFO] openclaw:discord:interaction - 使用嵌入回复交互
[DEBUG] openclaw:discord:interaction - 响应已发送:200 OK
退出代码验证
# 运行验证测试后
echo $?
# 预期:0(成功)
⚠️ 常见陷阱
环境特定陷阱
- WSL2 时序问题: WSL2 时钟同步可能导致交互响应超时。Discord 交互需要在 3 秒内响应。使用
ntpd或wsl2-hibernate变通方法。 - Docker 容器超时: 如果在 Docker 中运行,确保容器时钟与主机同步。运行
docker run --cap-add=SYS_TIME或使用timedatectl set-ntp true同步。 - Windows Defender 防火墙: 可能在私信环境中阻止 WebSocket 连接。为 Discord 的网关 IP 添加例外。
配置错误
- 缺失 Intent: 没有
Guildsintent,私信交互可能无法正确注册 - 隐式 Ephemeral: 某些配置默认为
ephemeral: true,这可能导致 "Done." 出现在意外位置 - 过时缓存: 本地缓存的旧命令定义可能覆盖注册更新
处理器反模式
- 未等待异步调用:
// 错误 interaction.deferReply(); fetchStatusData().then(data => { interaction.editReply({ embeds: [data] }); // 'this' 上下文丢失 });// 正确 await interaction.deferReply(); const data = await fetchStatusData(); await interaction.editReply({ embeds: [data] });
- 吞没的异常: 空的 catch 块会阻止调试
// 错误 try { ... } catch (e) {}// 正确 try { … } catch (e) { console.error(‘状态命令失败:’, e); throw e; // 或优雅处理 }
- 竞态条件: 多次快速命令调用可能与共享状态冲突
模型/提供者边缘情况
- Opus 4.6 特定: 某些数据字段在模型上下文冷启动时可能为
null,导致嵌入构建静默失败 - 速率限制: Discord 私信交互有更严格的速率限制;确保请求去抖动
🔗 相关错误
InteractionNotReplied:尝试编辑从未发送的回复时抛出。表现为 Discord API 错误 "Unknown Message"。50027: Invalid WebSocket State:交互到达但连接在响应发送前关闭。40060: Interaction Already Acknowledged:在deferReply()后尝试调用reply()而未使用editReply()。50013: Missing Permissions:机器人缺少SEND_MESSAGES或EMBED_LINKS权限,导致嵌入失败。- #2847: 私信中忽略斜杠命令 ephemeral 设置:影响 OpenClaw 适配器的相关 Discord API 行为变更。
- #3156: 冷启动时 deferReply() 静默失败:异步处理器初始化导致竞态条件。
- #3291: v2.3.0 适配器更新后状态命令回归:此精确回归模式的直接先例。