概述

Mattermost 是 fries-mac 与用户通信的主要平台(235条消息)。配置涉及服务器地址设置、Bot 账号绑定、文件发送功能、会话管理等方面。服务器部署在 mm.dora.restry.cn。

关键事件

  • 2026-03-03: 修复 Mattermost 服务器地址错误(应为 mm.dora.restry.cn)
  • 2026-03-03: 要求将配置信息准确记录,避免反复出错
  • 2026-03-07: 在 tiger-host 上安装 Supabase(参考官方 Docker 文档)
  • 2026-03-10: 处理 /compact/new/reset 等命令
  • 2026-03-17: 新建会话,切换模型到 claude-opus-4.6
  • 2026-04-04: 持续进行配置维护和更新

2026-05-10 OpenClaw 在 MM 的 block streaming 协议(cspy MM client 修复实证)

wechat-bot-tickets cspy MM client 5-10 流式聚合 bug 才搞清的事实,沉淀给所有写「等 OpenClaw bot 在 MM 出完整 reply」逻辑的代码:

OpenClaw 文档 https://openclaw.ai/concepts/streaming + /channels/mattermost

  1. Block streaming,不是 token-delta,不是 edit 同条 post:assistant 流式输出按 block flush 成多条独立 channel 消息。在 MM 上表现为发 N 条 post,全部 create_at 同一毫秒,前 N-1 条 message="" 空 post,只有最后 1 条有真实内容;流式中每条又会被 edit 多次(edit_at 持续若干秒后稳定)。
  2. CoalescingblockStreamingCoalesce.idleMs / minChars / maxChars,模型 idle 即 flush。idleMs 是「流式结束」的唯一信号(不是 done 事件)。
  3. MM channel 默认行为channels.mattermost.streaming 默认 off,只发 final reply;设 streaming.mode: "block" 才走多消息模式。

正确的「等完整 reply」算法(实证 from cspy commit 58befa2):

  • 整 channel 维度跟 max(update_at),任何 post 的 update 都算「还在动」
  • 静默窗口 30s(远大于默认 idleMs)才认定流式结束
  • final reply = 按 update_at 倒序找第一个 trim().length > 0 的 post
  • timeout 兜底:deadline 到了仍 pickFinal,找到就 return ok(标 viaTimeout

反模式:抓「第一条 message 非空的 post 立即 return」会把回复截断到几十字符(前面那条空 post 被绕过后,第一个 chunk 是开头几行就 return,后面真正长文那条根本没等)。

2026-05-11 MM WebSocket 客户端事件实测(cspy WS 架构升级)

5-11 用 cspy 真 token 直连 mm.cn.restry.cn WS 抓 90 秒事件流(wechat-bot-tickets WS 后端 + SSE typing UI 上线),坐实 OpenClaw bot 在 MM 上的 raw 行为:

[T=0.0s]  发出消息
[T=8.7s]  ⌨️ event=typing  user=nexora-mazu      ← 输入状态
[T=10.7s] ⌨️ event=typing  user=nexora-mazu      ← 心跳(每 ~2s 续期)
[T=13.8s] 📝 event=posted  ← post 内容是 JSON 字符串,需 JSON.parse(data.post)
[T=...]   📝 event=post_edited 多次 → edit_at 持续变直到稳定

写 MM WS 客户端的稳定算法(cspy lib/mm/ws-client.ts 实证):

  • lazy connect + 单例:多 listener 共享同一 socket
  • 重连指数退避 1s → 30s + 抖动;auth 用 seq_reply.status 判断成功
  • 过滤 broadcast.channel_id 防跨 channel 串台
  • subscribe 必须先于 postMessage —— 否则 race 错过 typing/posted 事件
  • 流式结束判定:typing 5s 不再来 + post 1.5s 不再变化双窗口;timeout 兜底 deadline 到了仍取最新有内容的 post(标 viaTimeout
  • escape hatchMM_WS_DISABLE=1 整个关掉 WS、MM_TRANSPORT=polling 切回旧路径
  • 测试注入:__setWsFactory(...) 注 mock socket

SSE 推前端:/api/mm/events 路由按 botMmUserId 解析对应 DM channel,把 ws-client 的事件流转 SSE,加 15s 心跳防 nginx/Caddy 切断。前端用 EventSource 接,typing 三点动画 + 流式追加。详见 wechat-bot-tickets 5-11 段。

2026-05-07 B2P 中国实例 mm.cn.restry.cn(azchina / MC_RG)

新增第二个 Mattermost 实例 mm.cn.restry.cn,部署在 Azure China(subscription = azchina,resource group MC_RG),目的是给 B2P 中国境内访问者提供低延迟通道(不走主站 mm.dora.restry.cn 出墙路径)。Docker compose 起 Mattermost + Postgres,反代走当地 caddy。

useraccesstokens 取 token 的坑

服务端建好 user / 启用 personal access token 后,Hermes 配置里需要的是 token 字段(实际 bearer),不是表里看到的 iduseraccesstokens 表的 id 是 token 的内部主键、token 才是实际请求 header 用的 Authorization: Bearer <token> 值。早期错把 id 当 token 配进去 → 401。

-- 正确取法
SELECT user_id, token FROM useraccesstokens WHERE user_id = '<bot user id>';
-- 把 token 列贴到 Hermes config / .env,不是 id 列

双实例策略

  • mm.dora.restry.cn — 国际主站 (Azure 香港 / 公网),OAuth/SSO 接 Logto,长期沉淀
  • mm.cn.restry.cn — 中国 B2P 入口,独立账号体系,不做 federation(避免 Azure China ↔ 国际跨境数据合规复杂度)
  • Bot 在两边各注册一份,配置 MM_* 变量分实例区分

5-08 复核:mm.cn.restry.cn 解析到 198.18.1.2 不是 fake-DNS

5-07 排查 claw-bot 沉默时一度怀疑本机 fake-DNS(198.18.0.0/15 是 RFC 2544 benchmark 段,常见于 Clash/V2Ray)。5-08 用公共 DNS(8.8.8.8、223.5.5.5)交叉解析仍是 198.18.1.2curl /api/v4/system/ping 200/88ms,13 个 bot WebSocket 全 ESTAB —— 确认是真实公网 A 记录(azchina anycast 落点),非伪造。后续判定 fake-DNS 前应先公共 DNS 比对 + 应用层 curl,不要看到 198.18.x 就下结论。真实根因详见 openclaw-config dmPolicy: open 必须显式 allowFrom: ["*"] 段。

5-07 claw-bot 上 Hermes Gateway 接 mm.cn.restry.cn + 13 个 agent bot 账号

Daddy 在 claw-bot (192.168.1.235) 上把本地 Hermes Agent 接入 mm.cn.restry.cn。流程:

  1. Mattermost → System Console → Bot Accounts 启用,建 hermes bot,token 9w9yxggejtn7jy5yfce3919u6o
  2. Hermes Gateway 用 systemd 跑,MATTERMOST_ALLOWED_USERS=matter、回复模式 thread
  3. 同时给 13 个 OpenClaw agent 各建一个同名 MM bot 账号nexora-ops / nexora-pyerp / nexora-xipu / nexora-mazu / nexora-laiya 等),但 Hermes Gateway 只能绑一个 bot token → 其它 bot 账号「有壳无魂」,发消息没人接。删掉了 4 个无对应 agent 的旧 bot:nexora-fe / nexora-be / nexora-qa / serverops(curl 频繁请求会被限流,prism-pm / prism-ui 一次没删成功)。
  4. 方向决定(Daddy 5-07 10:07):要让 OpenClaw agent 也能被 MM 直接 @,必须在 OpenClaw 侧 channels.mattermost.accounts 里把这些 bot 一一绑上,不在 Hermes 里绑。Hermes 这台只是接 hermes 这一个独立 agent 入口。

System admin token(azchina 实例):b4qoah9j63y8irq3cde1xoq96a,可用于 admin API 列 bots / 删 bot。

技术要点

  • 服务器地址: mm.dora.restry.cn
  • Bot Token: 通过 OpenClaw 网关配置
  • 文件发送: 需要通过 Mattermost API 上传附件
  • 会话管理: 支持 /compact(压缩上下文)、/new(新会话)、/reset(重置)

经验教训

  • 服务器地址等关键配置必须准确记录到记忆中
  • Bot 配置变更后需要重启 Gateway 才能生效
  • /compact 命令可用于压缩上下文窗口,避免 token 超限
  • 文件发送功能需要正确调用 API,不能仅输出文件路径

相关主题

Bot 开发端口约定

以下信息来源于 gatewaybot 的 Mattermost DM 聊天记录(2026-03-18)。

各项目 Bot 开发时的本地端口分配:

项目前端端口后端端口备注
Clawline Gateway30203021不使用 18800~18890 区间

用户明确要求不使用 18800~18890 区间端口,改用 3000 区间。开发站点通过 Caddy 反向代理暴露为 HTTPS(如 gw.dev.dora.restry.cn)。

注意事项:

  • Vite dev server 需要配置 server.allowedHosts 以允许域名访问
  • crypto.randomUUID() 在非 HTTPS 环境下不可用,需用 crypto.getRandomValues() 作为 fallback

Prism Bot 频道配置

以下信息来源于 bnef 的 Mattermost DM 聊天记录(2026-03-13)。

Prism 项目使用了 3 个 Mattermost 频道:

  • prism-general — 通用讨论和日报发布
  • prism-dev — 开发讨论
  • prism-standup — 每日站会自动推送

5 个 Bot 账号的 Mattermost 配置(在 openclaw.jsonchannels.mattermost.accounts 中):

BotdmPolicychatmode群消息触发
prism-pmopenonchar(前缀 pmpm 开头 或 @prism-pm
prism-archopenoncall@prism-arch
prism-dataopenoncall@prism-data
prism-uiopenoncall@prism-ui
prism-docsopenoncall@prism-docs

默认账号配置:dmPolicy: "pairing", groupPolicy: "open", allowFrom: ["*"]

Mattermost 服务器迁移(2026-03-15)

以下信息来源于 work_assistant 的 Mattermost DM 聊天记录。

原 Mattermost 服务器 mm.dora.restry.cn 运行在本地。为 Prism 项目创建了独立的新实例:

步骤内容
VM 准备transparent-n3 → 重建为 mattermost-server(保留磁盘+网卡)
DNSmattermost-server.chinanorth3.cloudapp.chinacloudapi.cn
镜像推送至 northacr.azurecr.cn(Azure China 北区,免密 pull)
部署Docker Compose: Mattermost + PostgreSQL + Caddy(HTTPS 自动证书)
Bot 迁移5 个 prism- bot 在新服务器上创建并转为 bot 账号,生成 access token
OpenClaw 更新Eagle 服务器 openclaw.json 的 baseUrl 和 token 切换到新服务器
清理旧服务器上停用 9 个用户 + 删除 3 个 prism 频道

Bot 死循环事件

新服务器上线后立即出现 Bot 互 @ 死循环——一个 Bot 回复时 @ 了另一个 Bot,触发连锁响应。

修复方案

  1. 配置层:groupAllowFrom 仅允许人类用户 ID 触发(allowlist 模式)
  2. 人设层:所有 Agent SOUL.md 明确禁止主动 @ Bot
  3. PM Bot 保持群聊全响应,其他 4 个 Bot 仅响应 allowlist 中的真人 @提及

注意:ignoreBots 是编造的不存在字段,正确方式为 groupPolicy: "allowlist" + groupAllowFrom

相关主题