Skip to content

Commit 60f13ce

Browse files
lmorchardclaude
andcommitted
feat(channels): add Mattermost channel support
Add Mattermost channel using WebSocket API v4 for receiving events and REST API v4 for sending. No external SDK — uses gorilla/websocket (existing dependency) and net/http. Features: - Thread-aware replies: channel messages auto-thread, DMs stay flat - Auto-reconnect with exponential backoff (5s-60s) - Message splitting at 4000 chars via channels.SplitMessage - Bot @mention stripping via configurable username field - Proper error classification using ClassifySendError/ClassifyNetError - MediaSender: file uploads via /api/v4/files - TypingCapable: typing indicator support - MessageEditor: edit existing posts - PlaceholderCapable: "Thinking..." placeholder that gets edited Config: channels.mattermost.enabled: bool channels.mattermost.url: server URL channels.mattermost.token: bot access token channels.mattermost.username: bot username for mention stripping channels.mattermost.reply_in_thread: auto-thread in channels (default true) channels.mattermost.allow_from: user ID allowlist channels.mattermost.group_trigger: group chat trigger config Includes: - Unit tests (TestNewMattermostChannel, TestParseChatID, TestBuildWSURL, TestStripBotMention) - README.md updates (chat apps table, collapsible setup guide) - Chinese docs at docs/channels/mattermost/README.zh.md (AI-generated, may need native speaker review) Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
1 parent b89f644 commit 60f13ce

File tree

9 files changed

+1033
-1
lines changed

9 files changed

+1033
-1
lines changed

README.md

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ That's it! You have a working AI assistant in 2 minutes.
308308

309309
## 💬 Chat Apps
310310

311-
Talk to your picoclaw through Telegram, Discord, WhatsApp, Matrix, QQ, DingTalk, LINE, or WeCom
311+
Talk to your picoclaw through Telegram, Discord, WhatsApp, Matrix, Mattermost, QQ, DingTalk, LINE, or WeCom
312312

313313
> **Note**: All webhook-based channels (LINE, WeCom, etc.) are served on a single shared Gateway HTTP server (`gateway.host`:`gateway.port`, default `127.0.0.1:18790`). There are no per-channel ports to configure. Note: Feishu uses WebSocket/SDK mode and does not use the shared HTTP webhook server.
314314
@@ -321,6 +321,7 @@ Talk to your picoclaw through Telegram, Discord, WhatsApp, Matrix, QQ, DingTalk,
321321
| **QQ** | Easy (AppID + AppSecret) |
322322
| **DingTalk** | Medium (app credentials) |
323323
| **LINE** | Medium (credentials + webhook URL) |
324+
| **Mattermost** | Easy (bot token) |
324325
| **WeCom AI Bot** | Medium (Token + AES key) |
325326

326327
<details>
@@ -436,6 +437,45 @@ picoclaw gateway
436437

437438
</details>
438439

440+
<details>
441+
<summary><b>Mattermost</b></summary>
442+
443+
**1. Create a bot account**
444+
445+
* Go to your Mattermost instance → Integrations → Bot Accounts → Add Bot Account
446+
* Copy the bot token
447+
448+
**2. Configure**
449+
450+
```json
451+
{
452+
"channels": {
453+
"mattermost": {
454+
"enabled": true,
455+
"url": "https://your-mattermost-server.com",
456+
"token": "YOUR_BOT_TOKEN",
457+
"username": "picoclaw",
458+
"reply_in_thread": true,
459+
"allow_from": ["YOUR_USER_ID"]
460+
}
461+
}
462+
}
463+
```
464+
465+
| Field | Type | Required | Description |
466+
| ---------------- | ------ | -------- | ----------------------------------------------- |
467+
| enabled | bool | Yes | Enable Mattermost channel |
468+
| url | string | Yes | Mattermost server URL |
469+
| token | string | Yes | Bot access token |
470+
| username | string | No | Bot username for @mention stripping |
471+
| reply_in_thread | bool | No | Auto-thread replies in channels (default: true) |
472+
| allow_from | array | No | User ID allowlist (empty = allow all) |
473+
| group_trigger | object | No | Group trigger config (mention_only, etc.) |
474+
475+
**3. Add the bot to channels** in Mattermost, then DM it or @mention it.
476+
477+
</details>
478+
439479
<details>
440480
<summary><b>WhatsApp</b> (native via whatsmeow)</summary>
441481

cmd/picoclaw/internal/gateway/helpers.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
_ "github.com/sipeed/picoclaw/pkg/channels/line"
2121
_ "github.com/sipeed/picoclaw/pkg/channels/maixcam"
2222
_ "github.com/sipeed/picoclaw/pkg/channels/matrix"
23+
_ "github.com/sipeed/picoclaw/pkg/channels/mattermost"
2324
_ "github.com/sipeed/picoclaw/pkg/channels/onebot"
2425
_ "github.com/sipeed/picoclaw/pkg/channels/pico"
2526
_ "github.com/sipeed/picoclaw/pkg/channels/qq"
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Mattermost
2+
3+
Mattermost 是一个开源的团队协作平台。PicoClaw 通过 WebSocket API v4 和 REST API v4 连接到 Mattermost 服务器,支持接收和发送消息、文件上传、线程回复和输入指示器。
4+
5+
## 配置
6+
7+
```json
8+
{
9+
"channels": {
10+
"mattermost": {
11+
"enabled": true,
12+
"url": "https://your-mattermost-server.com",
13+
"token": "YOUR_BOT_TOKEN",
14+
"username": "picoclaw",
15+
"reply_in_thread": true,
16+
"allow_from": ["YOUR_USER_ID"]
17+
}
18+
}
19+
}
20+
```
21+
22+
| 字段 | 类型 | 必填 | 描述 |
23+
| ---------------- | ------ | ---- | ---------------------------------------- |
24+
| enabled | bool || 是否启用 Mattermost 频道 |
25+
| url | string || Mattermost 服务器地址 |
26+
| token | string || 机器人访问令牌 |
27+
| username | string || 机器人用户名(用于去除 @提及) |
28+
| reply_in_thread | bool || 在频道中自动使用线程回复(默认:true) |
29+
| allow_from | array || 用户ID白名单,空表示允许所有用户 |
30+
| group_trigger | object || 群组触发设置 |
31+
32+
## 设置流程
33+
34+
1. 前往 Mattermost 管理后台 → 集成 → 机器人帐户 → 添加机器人帐户
35+
2. 复制机器人令牌
36+
3. 将令牌填入配置文件中
37+
4. 将机器人添加到需要的频道
38+
5. 通过私信或 @提及 与机器人交互
39+
40+
## 功能
41+
42+
- **线程回复**:频道消息自动使用线程,私信保持平面结构
43+
- **自动重连**:WebSocket 断开后自动重连(指数退避 5s-60s)
44+
- **消息分割**:超长消息自动分割(上限 4000 字符)
45+
- **文件上传**:支持通过 MediaSender 接口上传文件
46+
- **输入指示器**:支持显示"正在输入"状态
47+
- **消息编辑**:支持编辑已发送的消息
48+
- **占位消息**:发送"思考中..."占位消息,完成后替换为实际回复

pkg/channels/manager.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,10 @@ func (m *Manager) initChannels() error {
252252
m.initChannel("matrix", "Matrix")
253253
}
254254

255+
if m.config.Channels.Mattermost.Enabled && m.config.Channels.Mattermost.Token != "" {
256+
m.initChannel("mattermost", "Mattermost")
257+
}
258+
255259
if m.config.Channels.LINE.Enabled && m.config.Channels.LINE.ChannelAccessToken != "" {
256260
m.initChannel("line", "LINE")
257261
}

pkg/channels/mattermost/init.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package mattermost
2+
3+
import (
4+
"github.com/sipeed/picoclaw/pkg/bus"
5+
"github.com/sipeed/picoclaw/pkg/channels"
6+
"github.com/sipeed/picoclaw/pkg/config"
7+
)
8+
9+
func init() {
10+
channels.RegisterFactory("mattermost", func(cfg *config.Config, b *bus.MessageBus) (channels.Channel, error) {
11+
return NewMattermostChannel(cfg.Channels.Mattermost, b)
12+
})
13+
}

0 commit comments

Comments
 (0)