OpenclawFace 是一个一体化 OpenClaw 插件,提供:
- 双向 WebSocket 事件桥(
/ws) - 根据 OpenClaw 状态实时展示表情 UI(
/face) - NOMI 风格表达事件(
action_play/thought) - 天气输入(优先
weather.city,备选lat/lon) - 可配置调试显示(
debug=true显示状态面板,默认隐藏)
- 获取 OpenClaw 实时状态。
- 角色根据 OpenClaw 运行事件(message/llm/tool 等)自动切换状态。
- 支持外部手动触发表情,便于调试和验收。
- OpenClaw Gateway
- Node.js 18+ 与 npm
- 克隆仓库:
cd ~/.openclaw/workspace/plugin
git clone https://github.com/Wenzhao299/OpenclawFace.git- 安装依赖:
cd ~/.openclaw/workspace/plugin/OpenclawFace
npm i-
将插件配置写入
~/.openclaw/openclaw.json(见下方最小配置)。 -
重启 OpenClaw Gateway。
将以下片段合并到 ~/.openclaw/openclaw.json:
{
"plugins": {
"load": {
"paths": [
"~/.openclaw/workspace/plugin/OpenclawFace"
]
},
"entries": {
"OpenclawFace": {
"enabled": true,
"config": {
"bind": "0.0.0.0",
"port": 8787,
"path": "/ws",
"token": "replace-with-your-token",
"debug": false,
"ui": {
"enabled": true,
"path": "/face",
"defaultToUi": true
},
"weather": {
"enabled": true,
"city": "Shanghai",
"pollMs": 900000
},
"nomi": {
"autoTouchReact": true
}
}
}
}
}
}说明:
weather.city优先于weather.lat/lon。- 城市解析失败时会发出
weather_error,并回退到经纬度。 debug=false时 UI 顶部/底部状态信息默认隐藏;设为true可显示调试状态。
-
打开 UI:
http://<host>:8787/face/ -
如果启用了
token:http://<host>:8787/face/?token=<token> -
WS 连接地址:
ws://<host>:8787/ws?token=<token> -
Debug 显示开关: 在
openclaw.json中设置config.debug(true显示状态,false隐藏)。
消息通用结构:
{
"v": 1,
"type": "ui",
"name": "action_play",
"ts": 1700000000000,
"data": {}
}字段含义:
v: 协议版本type: 事件分组(gateway/session/message/agent/llm/tool/log/ui/expression)name: 事件名ts: 时间戳(毫秒)ctx: 过滤后的上下文(可选)data: 事件数据
始终会发出的事件:
client_connectedclient_disconnectedclient_errorweather_updateweather_errorui_interactionaction_playthought
受 events.allow 控制的 OpenClaw Hook 事件:
message_received,message_sending,message_sentllm_input,llm_outputbefore_tool_call,after_tool_callbefore_agent_start,agent_end,subagent_spawning,subagent_spawned,subagent_endedsession_start,session_end,gateway_start,gateway_stop
ui_interactionaction_playthought
打开 http://<host>:8787/face/?token=<token>,执行:
const ws = new WebSocket(`ws://${location.host}/ws?token=<token>`);
const send = (name, data) => ws.send(JSON.stringify({ v: 1, type: 'ui', name, ts: Date.now(), data }));然后依次测试动作:
send('action_play', { action: 'tap_ack', durationMs: 1400, intensity: 0.9 }); // listening
send('action_play', { action: 'tool_focus', durationMs: 1400, intensity: 0.8 }); // tool
send('action_play', { action: 'speak', durationMs: 1200, intensity: 0.9 }); // speaking
send('action_play', { action: 'happy', durationMs: 1600, intensity: 0.9 });
send('action_play', { action: 'angry', durationMs: 1600, intensity: 0.9 });
send('action_play', { action: 'sad', durationMs: 1800, intensity: 0.9 });
send('action_play', { action: 'sleep', durationMs: 2200, intensity: 0.9 });
send('thought', { text: 'Manual thought test', mood: 'thinking', ttlMs: 5000 });listening:message_received或 pointer down/tapthinking:llm_inputtool:before_tool_callspeaking:message_senterror:client_error或weather_erroridle: 默认状态或临时状态超时后恢复
- 在插件配置中设置
"weather.city"。 - 重启插件。
- 在 WS 数据流中确认
weather_update负载。
-
UI 显示不是最新: 打开
http://<host>:8787/face/后Ctrl+F5强刷,并检查启动日志是否打印:[openclaw-face] ui directory: .../OpenclawFace/ui -
插件未加载: 确认
plugins.entries的键名是OpenclawFace(必须与 manifest 的id完全一致)。 -
WS 无法连接: 检查
bind/port/path/token与网络防火墙配置。
- 局域网暴露时建议启用
token。 includeMessageContent与includeToolParams默认关闭,建议保持默认。
见 LICENSE。