synodeai
v1.3.0
Published
OpenClaw GeWe channel plugin
Readme
SyNodeAi OpenClaw Plugin
基于 SyNodeAi API + Webhook 回调的 OpenClaw 微信通道插件。
安装
从 npm 安装
openclaw plugins install synodeai从本地目录安装
openclaw plugins install /path/to/synodeai或使用软链接(便于开发调试):
openclaw plugins install --link /path/to/synodeai从归档安装
OpenClaw 支持本地 .zip / .tgz / .tar.gz / .tar 归档:
openclaw plugins install ./synodeai.tgz安装或启用插件后需要重启 Gateway。
配置方式(二选一)
安装完成后可任选一种方式完成配置:
方式 A:Onboarding 向导
openclaw onboard在通道列表中选择 SyNodeAi,按提示填写 token、appId、webhook,以及可选的 mediaPublicUrl/S3 媒体配置。
方式 B:直接编辑配置文件
直接编辑 ~/.openclaw/openclaw.json 的 channels.synodeai 段落(见下方示例)。
完整配置手册见:docs/openclaw-json-config.md
配置
插件配置放在 ~/.openclaw/openclaw.json 的 channels.synodeai,并确保通道开启(示例仅保留必填/常用字段):
简短配置
{
"channels": {
"synodeai": {
"enabled": true,
"token": "<synodeai-token>",
"webhookHost": "0.0.0.0",
"webhookPort": 4399,
"webhookPath": "/webhook",
"autoQuoteReply": false,
"allowFrom": [
],
"dmPolicy": "open",
"groupPolicy": "open",
"groups": {
"*": {
"trigger": {
"mode": "at"
},
"reply": {
"mode": "quote_source"
}
}
}
}
}
}完整参数说明:
webhookHost/webhookPort/webhookPath:SyNodeAi 回调入口(需公网可达,常配合 FRP)。mediaPath:本地媒体服务的路由前缀(默认/synodeai-media)。mediaPublicUrl:本地反代回退时的公网地址前缀(可选)。配置后会自动拼接媒体 ID;通常应与mediaPath对齐。s3Enabled:是否启用 S3 兼容上传。s3Endpoint/s3Region/s3Bucket/s3AccessKeyId/s3SecretAccessKey:S3 兼容服务连接参数。s3SessionToken:临时凭证可选字段。s3ForcePathStyle:是否启用 path-style(部分 S3 兼容服务需要)。s3UrlMode:public或presigned(默认public)。s3PublicBaseUrl:public模式下用于拼接可访问 URL(必填)。s3PresignExpiresSec:presigned模式签名有效期(默认 3600 秒)。s3KeyPrefix:对象 key 前缀(默认synodeai/outbound)。allowFrom:允许私聊触发的微信 ID(或在群里走 allowlist 规则)。voiceAutoConvert:自动将音频转为 silk(默认开启;设为false可关闭)。silkAutoDownload:自动下载rust-silk(默认开启;可关闭后自行配置voiceSilkPath/voiceDecodePath)。silkVersion:自动下载的rust-silk版本(latest会自动清理旧版本)。silkBaseUrl:自定义下载源(默认 GitHub Releases)。silkInstallDir:自定义安装目录(默认~/.openclaw/tools/rust-silk/<version>)。silkAllowUnverified:校验文件缺失时是否允许继续(默认false)。silkSha256:手动指定下载包 SHA256(用于私有源或校验文件缺失场景)。apiBaseUrl:SyNodeAi API 地址(默认https://www.synodeaiapi.com)。voiceFfmpegPath/videoFfmpegPath/videoFfprobePath:自定义 ffmpeg/ffprobe 路径。voiceSilkPath/voiceSilkArgs:自定义 silk 编码器路径和参数(不使用自动下载时)。voiceSilkPipe:是否启用 ffmpeg+rust-silk 的 stdin/stdout 管道(默认关闭;失败会回退到临时文件)。- 低频/非高并发且磁盘压力不高时,推荐临时文件方案(更稳定/更快)。
- 高频/多并发或磁盘压力大时,推荐 pipe 方案(减少磁盘 IO)。
voiceDecodePath/voiceDecodeArgs/voiceDecodeOutput:自定义 silk 解码器(入站语音转写用)。mediaMaxMb:上传媒体大小上限(默认 20MB)。downloadMinDelayMs/downloadMaxDelayMs:入站媒体下载节流。autoQuoteReply:是否开启replyToId + 纯文本自动引用回复(默认开启;设为false可关闭)。
群聊/私聊触发与回复规则
groups 和 dms 都支持 * 默认项 + 精确项覆写:
groups["*"]/groups["<roomId>@chatroom"]dms["*"]/dms["<wxid>"]
局部规则可继续搭配既有字段一起使用,例如 allowFrom、skills、systemPrompt、tools(仅群聊)。
群聊触发
groups[*].trigger.mode 支持:
at:只有被@时触发quote:只有引用机器人消息时触发at_or_quote:@或引用机器人消息都触发any_message:任何消息都触发
群聊默认值是 at。
群聊回复
groups[*].reply.mode 支持:
plain:普通回复quote_source:首条回复自动引用当前入站消息at_sender:首条文本回复自动@发送者quote_and_at:首条文本回复同时引用并@;非文本回复会自动退化为quote_source
群聊默认值会跟随 autoQuoteReply:
- 未配置或为
true:默认quote_source - 显式设为
false:默认plain
私聊触发与回复
dms[*].trigger.mode 支持:
any_messagequote
dms[*].reply.mode 支持:
plainquote_source
私聊默认触发是 any_message。私聊默认回复也会跟随 autoQuoteReply 回退到 quote_source 或 plain。
兼容旧配置
requireMention: true/false仍然可用,会分别映射到群聊trigger.mode = "at"/"any_message"- 新的
trigger/reply配置优先级更高 autoQuoteReply现在主要用于“未显式配置reply.mode时”的默认值回退
示例:
{
"channels": {
"synodeai": {
"groupPolicy": "open",
"groups": {
"*": {
"trigger": { "mode": "at" },
"reply": { "mode": "quote_source" }
},
"project-room@chatroom": {
"trigger": { "mode": "at_or_quote" },
"reply": { "mode": "quote_and_at" },
"skills": ["project-skill"]
},
"ops-room@chatroom": {
"trigger": { "mode": "any_message" },
"reply": { "mode": "plain" }
}
},
"dms": {
"*": {
"reply": { "mode": "quote_source" }
},
"wxid_special": {
"trigger": { "mode": "quote" },
"systemPrompt": "Only handle quoted follow-ups."
}
}
}
}
}目录、Allowlist 与状态
SyNodeAi 现在补齐了目录、标准 allowlist 适配和状态摘要。
目录
目录会混合这些来源:
allowFrom、groupAllowFrom、dms、groups- 顶层
bindings[]里命中的 SyNodeAi 群 - 运行中见过的私聊对象、群、群成员
支持的目录能力:
self:查看当前账号自己的wxid和昵称listPeers:查看已知私聊对象listGroups:查看已知群listGroupMembers:按需读取某个群的实时成员列表
其中 listGroupMembers 会 live 调用 SyNodeAi 的 getChatroomInfo,结果也会反哺后续名字解析。
Allowlist
标准 /allowlist 入口负责顶层两类名单:
- 私聊:
allowFrom - 群发言人:
groupAllowFrom
如果你要管理“某一个群自己的 groups.<groupId>.allowFrom 覆盖”,请用插件工具:
synodeai_manage_group_allowlist
它支持:
inspectaddremovereplaceclear
示例:
{
"mode": "replace",
"groupId": "ops-room@chatroom",
"entries": ["wxid_admin_1", "wxid_admin_2"]
}如果你就在目标群里调用,groupId 可以省略;工具会自动用当前群。
状态
SyNodeAi 的状态页现在会额外显示:
- API 是否可达、探测延迟
- 当前账号自己的
wxid/ 昵称 - 已知私聊对象数、已知群数、已缓存群成员数
- 显式
bindings[]数量 - 群局部 allowlist 覆盖数量
- pairing 本地 allow-from 数量
把群绑定到 Agent / ACP
除了 channels.synodeai 这一段插件配置,SyNodeAi 还支持配合 OpenClaw 顶层 bindings[] 使用。
可以把它理解成两层:
- 顶层
bindings[]决定“这个群/私聊归哪个 agent,或者归哪个 ACP 持久会话” groups.<groupId>.bindingIdentity决定“绑定以后,机器人在这个群里显示成什么身份”
绑定到普通 Agent
下面这个例子表示:ops-room@chatroom 这个群固定交给 ops agent 处理。
{
"bindings": [
{
"type": "route",
"agentId": "ops",
"match": {
"channel": "synodeai",
"accountId": "work",
"peer": {
"kind": "group",
"id": "ops-room@chatroom"
}
}
}
],
"channels": {
"synodeai": {
"accounts": {
"work": {
"groups": {
"ops-room@chatroom": {
"trigger": { "mode": "at_or_quote" },
"reply": { "mode": "quote_and_at" }
}
}
}
}
}
}
}说明:
match.channel写synodeaimatch.accountId可写具体账号,也可以写"*"- 群聊
peer.kind写"group",peer.id直接写群ID@chatroom bindings[]用于描述群或私聊与 agent 的绑定关系
绑定到 ACP 持久会话
下面这个例子表示:这个群固定进入 codex agent 的一个 ACP 持久会话。
{
"bindings": [
{
"type": "acp",
"agentId": "codex",
"match": {
"channel": "synodeai",
"accountId": "work",
"peer": {
"kind": "group",
"id": "repo-room@chatroom"
}
},
"acp": {
"label": "repo-room",
"mode": "persistent",
"cwd": "/workspace/repo-a",
"backend": "acpx"
}
}
]
}说明:
- SyNodeAi 群没有 Telegram topic / Feishu thread 这种层级,所以 ACP 绑定语义是“整群共享一个 ACP 会话”
- 同一个群只配置一种绑定方式,不要同时配置普通 route binding 和 ACP binding
群里的绑定身份
groups.<groupId>.bindingIdentity 用来描述“这个群已经绑定到 agent 后,机器人在群里应该显示成什么样”。
当前只同步两项:
- 机器人自己的群昵称
selfNickname - 这个群在机器人侧的备注
remark
不会改群名。
{
"channels": {
"synodeai": {
"groups": {
"*": {
"bindingIdentity": {
"enabled": true,
"selfNickname": { "source": "agent_name" },
"remark": { "source": "agent_id" }
}
},
"repo-room@chatroom": {
"bindingIdentity": {
"remark": { "source": "name_and_id" }
}
}
}
}
}
}默认值:
enabled = trueselfNickname.source = "agent_name"remark.source = "agent_id"
可选值:
selfNickname.source:agent_name | agent_id | literalremark.source:agent_id | agent_name | name_and_id | literal
当 source = "literal" 时,需要额外提供 value。
手动同步群绑定身份
插件提供了一个仅 owner 可用的工具:synodeai_sync_group_binding。
它不会在启动时自动改微信群信息,而是采用手动同步流程:
- 先配置顶层
bindings[] - 再按需配置
groups.<groupId>.bindingIdentity - 最后由 owner 调用
synodeai_sync_group_binding
工具参数:
{
"mode": "inspect", // inspect | dry_run | apply
"groupId": "repo-room@chatroom", // 可选;在当前绑定群里可自动推断
"accountId": "work", // 可选;默认当前账号
"syncSelfNickname": true,
"syncRemark": true
}三个模式的区别:
inspect:查看当前值、期望值、会改哪些字段dry_run:和inspect类似,但明确用于“准备执行前预演”apply:只在字段真的发生变化时调用 SyNodeAi API
使用限制:
- 只接受“有显式 binding 的群”,不会对仅靠默认 main route 命中的群做推断同步
bindingIdentity.enabled = false的群不能执行同步- 在非群上下文里调用时,必须显式传
groupId
发送媒体时的 URL 策略:
- 本地文件:优先上传 S3,失败回退
mediaPublicUrl本地反代。 - 公网 URL:先尝试原 URL 发送,失败后再尝试上传 S3,仍失败回退本地反代。
富消息与消息复用
除了直接构造 channelData["synodeai"],现在也可以通过共享 message 工具走标准动作:
sendreplyunsend
并在参数里附带一个 synodeai 对象来表达微信专属语义。
示例:在当前群里回复并做部分引用
{
"action": "reply",
"message": "收到,我接着处理",
"synodeai": {
"quote": {
"partialText": "需要继续跟进的那一段"
}
}
}示例:撤回一条已经发出的消息
{
"action": "unsend",
"to": "ops-room@chatroom",
"messageId": "10001",
"newMessageId": "10002",
"createTime": "1710000002"
}插件支持通过 channelData["synodeai"] 传入 SyNodeAi 专有消息语义。结构如下:
appMsg: { appmsg }:直接发送<appmsg>XML。quoteReply: { svrid?, title?, atWxid? }:发送引用回复;未提供svrid时会回退到宿主replyToId。emoji: { emojiMd5, emojiSize }:发送表情。nameCard: { nickName, nameCardWxid }:发送名片。miniApp: { miniAppId, displayName, pagePath, coverImgUrl, title, userName }:发送小程序。revoke: { msgId, newMsgId, createTime }:撤回指定消息。forward: { kind, xml, coverImgUrl? }:复用已存在消息 XML 进行二次转发。kind支持image | video | file | link | miniAppminiApp转发额外需要coverImgUrl
示例:
{
"channelData": {
"synodeai": {
"forward": {
"kind": "link",
"xml": "<msg>...</msg>"
}
}
}
}引用回复示例:
{
"channelData": {
"synodeai": {
"quoteReply": {
"svrid": "208008054840614808",
"title": "这条是引用回复",
"atWxid": "wxid_member_optional"
}
}
}
}另外,普通文本回复如果带有宿主 replyToId,插件默认会自动映射为 SyNodeAi 的引用回复气泡;媒体、链接、小程序、撤回、转发等既有富消息分支不会被这条自动桥接抢占。若不希望自动引用,可在配置里设置 autoQuoteReply: false。
如果希望让模型主动发“部分引用”,SyNodeAi 通道会识别回复末尾的一行隐藏指令:
[[GEWE_QUOTE_PARTIAL:要引用的原文片段]]插件会在发送前剥离这行指令,并自动转成 quoteReply.partialText。通常配合宿主 replyToId 一起使用,用来引用当前正在回复的那条消息中的某一段文字。
入站 appmsg 现在会尽量保留复用素材,并在上下文中附带:
MsgType:原始 SyNodeAimsgTypeSyNodeAiXml:原始 XMLSyNodeAiAppMsgXml:appmsgXMLSyNodeAiAppMsgType:appmsg的typeSyNodeAiQuoteXml:引用消息原始 XML(当type=57时)SyNodeAiQuoteTitle:引用回复正文SyNodeAiQuoteType:被引用消息类型SyNodeAiQuoteSvrid:被引用消息 sidSyNodeAiQuoteFromUsr/SyNodeAiQuoteChatUsr/SyNodeAiQuoteDisplayNameSyNodeAiQuoteContent/SyNodeAiQuoteMsgSource
这意味着收到链接、文件通知、引用消息或其他未专门解析的 appmsg 后,可以直接取上下文里的 XML 和引用元数据,再走 forward / appMsg / quoteReply 能力完成复用或继续回复。
配置变更后需重启 Gateway。
高级用法:让未安装插件也出现在 onboarding 列表
默认情况下,只有已安装的插件会出现在 onboarding 列表中。
如果你希望“未安装时也能在列表中展示”,需要配置本地 catalog:
~/.openclaw/plugins/catalog.json示例(添加一次即可):
{
"entries": [
{
"name": "synodeai",
"openclaw": {
"channel": {
"id": "synodeai",
"label": "SyNodeAi",
"selectionLabel": "WeChat (SyNodeAi)",
"detailLabel": "WeChat (SyNodeAi)",
"docsPath": "/channels/synodeai",
"docsLabel": "synodeai",
"blurb": "WeChat channel via SyNodeAi API and webhook callbacks.",
"aliases": ["synodeai", "synodeai", "wechat", "wx"],
"order": 72,
"quickstartAllowFrom": true
},
"install": {
"npmSpec": "synodeai",
"defaultChoice": "npm"
}
}
}
]
}现在插件已支持 onboarding:选择 SyNodeAi 通道后会提示填写 token/appId/webhook/mediaPublicUrl 等配置。
依赖
发布(维护者)
仓库已内置 tag 驱动的 npm 发布工作流:
- 工作流文件:
.github/workflows/publish-npm.yml - 触发方式:推送
v*tag - 发布前会自动校验:
- tag 版本号与
package.json.version一致 CHANGELOG.md已包含对应版本标题npm ci、npm test、npm pack --dry-run全部通过
- tag 版本号与
首次启用前,还需要在 npm 包设置里把这个仓库配置成 Trusted Publisher:
- Repository:
Wangnov/synodeai - Workflow filename:
publish-npm.yml
日常发版流程:
git commit -m "release: 2026.3.23"
git tag v2026.3.23
git push origin main v2026.3.23npm 依赖
zod
peer 依赖
openclaw(>= 2026.1.29)
系统级工具
ffmpeg/ffprobe(用于视频缩略图与时长)rust-silk(出站语音转 silk + 入站语音解码;支持自动下载)- 或者自行安装
silk-encoder/silk-decoder并在配置中指定路径
网络/服务依赖
- SyNodeAi API 服务
- Webhook 回调需要公网可达(可配合 FRP)
- 媒体对外地址(
mediaPublicUrl)
