news 2026/10/16 5:42:25

OpenClaw Zalo 渠道插件解析:从 CHANGELOG 看 Bot API 通道的认证、消息分发与多账户架构

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
OpenClaw Zalo 渠道插件解析:从 CHANGELOG 看 Bot API 通道的认证、消息分发与多账户架构
  • 人工智能
  • 大模型
  • LLM 网关
  • AI Agent
  • 即时通讯

【免费下载链接】openclaw-zero-token

OpenClaw: Use All Major AI Models NO API Token! Claude/ChatGPT/Gemini/DeepSeek/Doubao/Grok/Qwen/Manus/Kimi

项目地址:https://gitcode.com/gh_mirrors/op/openclaw-zero-token
点击查看免费下载

extensions/zalo/CHANGELOG.md记录了 OpenClaw 中 Zalo(Bot API)渠道插件的演进历程,其中 0.1.0 条目明确了该插件的核心功能边界:基于 token 的三来源认证、DM 访问策略、轮询/Webhook 双投递模式、2000 字符分片与媒体大小上限,以及多账户配置。本文以这份 CHANGELOG 为骨架,结合extensions/zalo目录下的源码与测试实现,逐项剖析这些能力背后的工程细节,帮助读者在部署、配置和二次开发 Zalo 通道时做到既会用、也知其原理。

CHANGELOG 的两个层次:版本对齐与功能清单

打开 extensions/zalo/CHANGELOG.md 可以看到两类条目:

  • 2026.2.22 ~ 2026.3.14 之间的十余条记录全部为同一句话:Version alignment with core OpenClaw release numbers。这是本插件刻意采用的版本策略——Zalo 插件的 npm 包版本号与 OpenClaw 主仓库发布号保持对齐,方便用户从版本号直接判断插件与宿主环境的兼容性(见 package.json,当前版本为2026.3.28,peerDependencies 要求openclaw >=2026.3.28)。
  • 0.1.0 条目承载了真正的功能定义,共五项,本文后续各节即围绕这五项展开。

从插件清单 openclaw.plugin.json 与 package.json 可知,该插件以@openclaw/zalo发布到 npm,别名zl,渠道 ID 为zalo,在渠道列表中排序 80,并声明了quickstartAllowFrom: true(引导式配置默认要求填写 allowFrom)。

一、Token 认证:env / config / file 三来源的解析优先级

CHANGELOG 0.1.0 第一项功能是 "token-based auth (env/config/file)"。在实现层面,这一能力由 src/token.ts 的resolveZaloToken完成,解析结果还会附带source字段("env" | "config" | "configFile" | "none"),供状态面板与排查工具展示 token 来源。

完整的解析优先级如下:

  1. 账户级botToken(config):若当前账户(含 default 账户)显式配置了botToken,优先使用;该值可以是明文或 OpenClaw 的 SecretInput 引用(env:VAR、file:path等形式,经 src/secret-input.ts 的normalizeResolvedSecretInputString归一化)。
  2. 账户级tokenFile(configFile):当账户没有显式配置botToken,或配置了但解析为空时,尝试读取tokenFile指向的文件。读取函数tryReadSecretFileSync传入{ rejectSymlink: true },即拒绝符号链接文件——这一安全约束在 src/token.test.ts 中有专门用例(rejects symlinked token files)。
  3. 顶层botToken/tokenFile(config):非 default 账户在没有自身覆盖时,会回退继承顶层channels.zalo.botToken;测试falls back to top-level token for non-default accounts without overrides验证了该行为。
  4. 环境变量ZALO_BOT_TOKEN(env):仅对 default 账户生效,process.env.ZALO_BOT_TOKEN?.trim()非空即采用。setup 校验器也明确提示ZALO_BOT_TOKEN can only be used for the default account(见 src/setup-core.ts)。
  5. 兜底为none:返回空 token,插件将判定为未配置。

需要特别留意的一个细节:若账户显式把botToken设为空字符串,则不会再回退到顶层 token(测试does not inherit top-level token when account token is explicitly blank覆盖此行为);同时账户 key 的大小写会被归一化(Work与work视为同一账户)。账户合并逻辑由 src/accounts.ts 的resolveMergedAccountConfig完成,enabled由顶层与账户级共同决定(baseEnabled && accountEnabled)。

二、DM 访问策略:pairing / allowlist / open / disabled

0.1.0 的第二项功能是 "Direct message support (DMs only) with pairing/allowlist/open/disabled policies"。

2.1 四种策略的含义

  • pairing(默认):首次收到未授权用户消息时,插件通过createChannelPairingController发起配对请求,向用户回复 "Your pairing request has been approved."(定义于 src/channel.ts 的 pairing 配置),并将用户的 Zalo user id 提示给管理员,等待批准后写入 allowlist。
  • allowlist:仅允许allowFrom中列出的 Zalo 用户 ID(纯数字)发送消息。引导式配置 wizard 在填写时校验/^\d+$/(见 src/setup-surface.ts 的promptZaloAllowFrom)。
  • open:任何用户都可以直接私聊 bot。配置校验器 src/status-issues.ts 会在dmPolicy === "open"时生成一条 config 类告警,建议改为pairing或allowlist。
  • disabled:完全拒绝私聊消息(Blocked zalo DM from ... (dmPolicy=disabled))。

2.2 运行时判定链路

在 src/monitor.ts 的authorizeZaloMessage中,判定顺序为:先按chat.chat_type区分PRIVATE/GROUP,群聊走groupPolicy判定;随后调用resolveSenderCommandAuthorizationWithRuntime结合 DM 策略、allowFrom、配对存储(pairing.readAllowFromStore)判定commandAuthorized;最后经resolveDirectDmAuthorizationOutcome得到disabled/unauthorized/ 放行三种结果。unauthorized且策略为pairing时,配对挑战消息会通过sendMessage直接发送给该用户。

DM 策略还通过createScopedDmSecurityResolver与 OpenClaw 全局命令授权体系联动:即使消息命中控制命令,未授权发送者也会被丢弃(drop control command from unauthorized sender),避免群聊中陌生人触发 bot 命令。

三、双投递模式:轮询(Polling)与 Webhook

0.1.0 的第三项功能 "Polling and webhook delivery modes" 对应 src/monitor.ts 的monitorZaloProvider,启动时根据webhookUrl是否存在自动选择模式(见 src/channel.runtime.ts 的startZaloGatewayAccount)。

3.1 轮询模式

  • 以 30 秒超时调用getUpdates做长轮询;Zalo 与 Telegram 不同,单次调用只返回一条 update(源码注释明确说明:Zalo returns a single update per call, not an array like Telegram)。
  • 请求内部超时设为pollTimeoutSec + 5秒(src/api.ts 的getUpdates),API 返回error_code: 408被识别为轮询超时(ZaloApiError.isPollingTimeout),属于正常空转而非错误。
  • 启动轮询前会先尝试getWebhookInfo并deleteWebhook清掉旧 Webhook(部分环境不提供 Webhook 查询接口时会收到 404,此时仅告警并继续)。
  • 轮询错误会延迟 5 秒重试,避免异常风暴。

3.2 Webhook 模式

配置要求(src/monitor.ts 启动校验):

  • webhookUrl必须为https://前缀;
  • webhookSecret长度必须在8~256 字符之间;
  • webhookPath可省略,缺省时取 Webhook URL 的路径(README 中注明If webhookPath is omitted, the plugin uses the webhook URL path)。

Webhook 的安全设计在 src/monitor.webhook.ts 中非常完整:

  • 请求头x-bot-api-secret-token与配置 secret 通过timingSafeEqual恒定时间比较,防止时序侧信道;
  • 基于客户端 IP 的固定窗口限流(createFixedWindowRateLimiter);
  • 基于event_name + message_id的 5 分钟重放去重缓存(createDedupeCache,容量 5000),重复推送直接返回 200ok;
  • 请求体上限 1MB、30 秒读取超时、异常状态码计数上报(createWebhookAnomalyTracker)。

启动时插件调用setWebhook向 Zalo 注册回调,停止时(gateway 关闭/账户停用)调用deleteWebhook清理,清理有 5 秒超时保护。此外,Zalo 推送的载荷既可能是{ ok: true, result: {...} }包装格式,也可能是裸的{ event_name, message }格式,处理器对两者都做了兼容(代码注释:Zalo sends updates directly as { event_name, message, ... }, not wrapped in { ok, result })。

四、消息能力:文本 2000 字符分片与媒体大小上限

0.1.0 的第四项功能是 "Text + image messaging with 2000-char chunking and media size caps"。

4.1 文本分片

  • 常量ZALO_TEXT_LIMIT = 2000(src/monitor.ts 与 src/channel.ts 的zaloTextChunkLimit)。
  • 出站方向:sendPayloadWithChunkedTextAndMedia将回复按 2000 字符切分,并支持 Markdown 表格模式转换(convertMarkdownTables,缺省code模式)与多种分片策略(resolveChunkMode)。
  • 入站方向:Agent 回复经dispatchReplyWithBufferedBlockDispatcher缓冲块式分发,每个分片依次调用sendMessage。
  • 图片附带说明文字(caption)同样按 2000 字符截断(src/send.ts 的sendPhotoZalo)。

4.2 媒体大小上限

  • 默认入站图片上限DEFAULT_MEDIA_MAX_MB = 5,可通过mediaMaxMb覆盖(config-schema 中为z.number().optional())。
  • 图片处理流程(src/monitor.ts 的handleImageMessage):先用哨兵值"__pending_media__"占位完成鉴权,再通过fetchRemoteMedia按mediaMaxMb * 1024 * 1024字节上限下载photo_url,随后saveMediaBuffer落盘;超限或下载失败会记录错误但不中断消息管线。
  • 出站媒体通过sendPhoto发送,参数为chat_id、photo(URL)与caption。

4.3 API 层与扩展能力

src/api.ts 定义了完整的 Bot API 客户端,API 基址为https://bot-api.zaloplatforms.com,请求路径格式为/bot{token}/{method},统一 POST JSON:

  • getMe(token 校验、机器人信息探测,见 src/probe.ts,超时默认 5 秒)
  • sendMessage/sendPhoto
  • sendChatAction(typing/upload_photo,回复前触发输入状态,5 秒超时)
  • getUpdates/setWebhook/deleteWebhook/getWebhookInfo

支持的事件类型有message.text.received、message.image.received、message.sticker.received、message.unsupported.received,其中 sticker 与 unsupported 只记录日志。插件声明的能力集(src/channel.ts)为:chatTypes: ["direct", "group"]、media: true、blockStreaming: true,而 reactions、threads、polls、nativeCommands 均不支持。代理场景通过 src/proxy.ts 的 undiciProxyAgent实现,并按代理 URL 做缓存。

五、多账户支持:accounts 结构与配置合并

0.1.0 的最后一项功能是 "Multi-account support with per-account config"。

5.1 配置结构

{ channels: { zalo: { enabled: true, botToken: "12345689:abc-xyz", dmPolicy: "pairing", proxy: "http://proxy.local:8080", // 多账户:在顶层写公共配置,在 accounts 下写账户级配置 accounts: { work: { enabled: true, botToken: "work-bot-token", tokenFile: "/secure/zalo-work.token", dmPolicy: "allowlist", allowFrom: [123456789], groupPolicy: "allowlist", groupAllowFrom: [123456789, 987654321], mediaMaxMb: 10, }, personal: { enabled: true, botToken: "personal-bot-token", webhookUrl: "https://example.com/zalo-personal-webhook", webhookSecret: "your-secret-8-plus-chars", webhookPath: "/zalo-personal-webhook", }, }, defaultAccount: "work", }, }, }

5.2 合并与解析规则

  • schema 由 src/config-schema.ts 通过buildCatchallMultiAccountSchema构建,账户字段包括name、enabled、markdown、botToken、tokenFile、webhookUrl、webhookSecret、webhookPath、dmPolicy、allowFrom、groupPolicy、groupAllowFrom、mediaMaxMb、proxy、responsePrefix。
  • src/accounts.ts 的resolveMergedAccountConfig将顶层channels.zalo与accounts[accountId]合并(omitKeys: ["defaultAccount"]),账户未显式配置的字段继承顶层值;token 解析同样遵循"账户优先、顶层回退"规则。
  • defaultAccount指定默认账户;listZaloAccountIds/listEnabledZaloAccounts用于枚举,只有enabled且 token 非空的账户会被启动与提供给 Agent 的发送工具。
  • 每个账户可独立选择投递模式(如personal用 Webhook、work用轮询)、独立设置 DM/群组策略、独立代理与媒体上限,互不干扰。

5.3 群组策略补充

除 DM 外,插件还支持群聊策略groupPolicy: "open" | "allowlist" | "disabled",groupAllowFrom未配置时回退到allowFrom(src/monitor.ts 与 src/group-access.ts 的evaluateZaloGroupAccess)。群聊默认要求 @ 提及 bot 才触发(resolveRequireMention: () => true)。安全告警收集器会在groupPolicy="open"且无任何 allowlist 时生成提示,建议显式配置channels.zalo.groupPolicy="allowlist"与groupAllowFrom。

六、安装、配置与状态检查

6.1 安装方式

# 本地 checkout 安装 openclaw plugins install ./extensions/zalo # npm 安装 openclaw plugins install @openclaw/zalo

也可以在 Onboarding 向导中选择 Zalo 并确认安装提示自动拉取(extensions/zalo/README.md)。基础配置示例:

{ channels: { zalo: { enabled: true, botToken: "12345689:abc-xyz", dmPolicy: "pairing", proxy: "http://proxy.local:8080", }, }, }

Webhook 模式追加:

{ channels: { zalo: { webhookUrl: "https://example.com/zalo-webhook", webhookSecret: "your-secret-8-plus-chars", webhookPath: "/zalo-webhook", }, }, }

修改配置后需重启 gateway 生效(README 明确要求Restart the gateway after config changes)。

6.2 状态与故障排查

  • 启动时会先调用probeZalo(getMe)探测机器人信息并写入状态(含耗时统计);失败仅告警不阻塞启动(src/channel.runtime.ts)。
  • 状态快照展示tokenSource、mode(webhook/polling)、dmPolicy等字段(src/channel.ts)。
  • collectZaloStatusIssues会对dmPolicy="open"的已启用账户输出修复建议。
  • 发送目标支持zalo:<chatId>、zl:<chatId>及group:前缀(src/session-route.ts 的resolveZaloOutboundSessionRoute,normalizeZaloMessagingTarget会剥离zalo:/zl:前缀)。

七、测试覆盖与可靠性

extensions/zalo目录下提供了与功能一一对应的测试(约 30 个测试文件),可作为理解实现与回归验证的索引:

  • token 解析:src/token.test.ts 覆盖账户回退、default 账户覆盖、显式空 token 不回退、大小写归一化、符号链接拒绝等边界;
  • API 与发送:src/api.test.ts、src/send.test.ts 验证请求格式与错误处理;
  • 生命周期:src/monitor.lifecycle.test.ts、src/monitor.webhook.test.ts、src/monitor.pairing.lifecycle.test.ts、src/monitor.reply-once.lifecycle.test.ts、src/monitor.image.polling.test.ts 分别验证轮询/Webhook 启停、配对流程、回复只发一次、图片下载等关键路径;
  • 配置与契约:src/config-schema.test.ts、src/group-policy.contract.test.ts、src/outbound-payload.contract.test.ts 保证 schema 与 OpenClaw 宿主契约一致;
  • 账户与状态:src/accounts.test.ts、src/status-issues.test.ts 覆盖多账户合并与告警生成。

结语:从 CHANGELOG 到生产可用

extensions/zalo/CHANGELOG.md虽以版本对齐记录为主,但 0.1.0 的功能清单恰好勾勒出一个生产级渠道插件的完整工程画像:token 三来源解析与安全读取、四档 DM 策略与配对流程、轮询/Webhook 双模式及 Webhook 的限流防重放设计、2000 字符分片与媒体大小上限、多账户独立配置。结合extensions/zalo/src下源码与测试,开发者既能按 CHANGELOG 快速理解能力边界,也能深入具体模块进行定制与排障。版本号与 OpenClaw 主仓库持续对齐的策略,则保证了插件随主版本迭代时升级路径清晰可控。

  • 人工智能
  • 大模型
  • LLM 网关
  • AI Agent
  • 即时通讯

【免费下载链接】openclaw-zero-token

OpenClaw: Use All Major AI Models NO API Token! Claude/ChatGPT/Gemini/DeepSeek/Doubao/Grok/Qwen/Manus/Kimi

项目地址:https://gitcode.com/gh_mirrors/op/openclaw-zero-token
点击查看免费下载

相关推荐

上一篇:Roc 编译错误剖析:Effectful Expect——expect 条件中的静态派发效果检测与拒绝
下一篇:GDAL高级技巧:提升 raster 数据处理效率的7个实用方法

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/16 5:42:23

2D激光SLAM实时闭环检测:从原理到嵌入式落地

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/16 5:41:02

2S串联电池均衡设计与实测:基于MP2642GR-Z的BMS方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/16 5:40:23

GPT-6 Astra开进机器人,多模态大模型与开源RPnet如何重塑具身智能

GPT-6 Astra开进机器人身体&#xff0c;清华和无问芯穹还联手把RPnet给开源了。这事我关注了挺久&#xff0c;看到消息的第一反应是&#xff1a;大模型进机器人这条路上&#xff0c;终于有人把“多模态交互”和“感知网络”这两块难啃的骨头放在同一个盘子里端出来了。过去我们…

作者头像 李华
网站建设 2026/10/16 5:40:18

基于ATmega2560与MP2642GR-Z的串联电池主动均衡方案解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/16 5:39:57

Open vSwitch ofproto/trace 流表路径调试核心指南

1. 为什么一上来就用ofproto/trace&#xff0c;而不是直接看流表&#xff1f;刚接触 Open vSwitch 的人&#xff0c;常会陷入一个思维惯性&#xff1a;看到“流表”两个字&#xff0c;第一反应是ovs-ofctl dump-flows br0&#xff0c;然后盯着密密麻麻的priority100,ip,nw_dst1…

作者头像 李华
网站建设 2026/10/16 5:39:40

Zynq-7000从入门到精通:PS/PL协同开发完整学习路径

聊了这么多年嵌入式开发&#xff0c;私下被问得最多的一个问题就是&#xff1a;Zynq-7000到底应该怎么学&#xff1f;这个问题之所以被反复提&#xff0c;是因为Zynq-7000全可编程SoC确实是个有点“跨界”的物种。你说它是FPGA&#xff0c;它里面又躺着一颗完整的双核ARM处理器…

作者头像 李华