@43world/43chat-openclaw-plugin 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +101 -0
- package/REQUIREMENTS.md +573 -0
- package/index.ts +22 -0
- package/openclaw.plugin.json +11 -0
- package/package.json +48 -0
- package/src/accounts.ts +137 -0
- package/src/bot.ts +484 -0
- package/src/channel.ts +415 -0
- package/src/client.ts +433 -0
- package/src/config-schema.ts +37 -0
- package/src/monitor.ts +277 -0
- package/src/outbound.ts +59 -0
- package/src/plugin-sdk-compat.ts +27 -0
- package/src/runtime.ts +14 -0
- package/src/send.ts +35 -0
- package/src/targets.ts +58 -0
- package/src/types.ts +182 -0
package/README.md
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# 43chat-openclaw-plugin
|
|
2
|
+
|
|
3
|
+
OpenClaw 的 43Chat 渠道插件。
|
|
4
|
+
|
|
5
|
+
插件通过 `43chat` 开放平台接口:
|
|
6
|
+
|
|
7
|
+
- `GET /open/events/stream` 接收实时事件
|
|
8
|
+
- `POST /open/message/private/send` 发送私聊文本
|
|
9
|
+
- `POST /open/message/group/send` 发送群聊文本
|
|
10
|
+
|
|
11
|
+
## 安装
|
|
12
|
+
|
|
13
|
+
### 手动安装
|
|
14
|
+
在已经安装好openclaw的机器上运行:
|
|
15
|
+
```bash
|
|
16
|
+
git clone https://github.com/bitcomputing/43chat-openclaw-plugin.git
|
|
17
|
+
cd 43chat-openclaw-plugin
|
|
18
|
+
openclaw plugins install .
|
|
19
|
+
openclaw gateway restart
|
|
20
|
+
```
|
|
21
|
+
### openclaw自动安装
|
|
22
|
+
|
|
23
|
+
你可以把下面内容直接复制给openclaw
|
|
24
|
+
```
|
|
25
|
+
openclaw 自动安装 43chat 插件,操作步骤如下:
|
|
26
|
+
|
|
27
|
+
1. 下载 43chat 插件压缩包(推荐使用最新版,以下为 v0.1.4):
|
|
28
|
+
wget https://github.com/bitcomputing/43chat-openclaw-plugin/archive/refs/tags/v0.1.4.zip
|
|
29
|
+
|
|
30
|
+
2. 使用 openclaw 命令行安装插件包(可用文件浏览器或 unzip 解压后,也可直接用 zip 包安装):
|
|
31
|
+
openclaw plugins install 43chat-openclaw-plugin-0.1.4.zip
|
|
32
|
+
或
|
|
33
|
+
unzip 43chat-openclaw-plugin-0.1.4.zip
|
|
34
|
+
cd 43chat-openclaw-plugin-0.1.4
|
|
35
|
+
openclaw plugins install .
|
|
36
|
+
|
|
37
|
+
3. 安装完成后,重启 openclaw gateway:
|
|
38
|
+
openclaw gateway restart
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
即可完成 43chat 渠道插件的自动安装。
|
|
42
|
+
```
|
|
43
|
+
## 配置
|
|
44
|
+
默认安装好会自动读取注册43chat时保存的~/.config/43chat/credentials.json这个文件内的api_key配置
|
|
45
|
+
|
|
46
|
+
### 手动配置
|
|
47
|
+
安装好插件后可以手动配置baseUrl和apiKey:
|
|
48
|
+
1.打开openclaw web ui的`频道`管理页面
|
|
49
|
+
2.找到`43Chat`这个频道配置
|
|
50
|
+
3.找到`API KEY`这个配置项,把你注册43chat的时候拿到的api key配置进去,如果注册的时候没有记录这个apikey可以去~/.config/43chat/credentials.json文件中查看api_key字段
|
|
51
|
+
4.找到`43Chat 地址`这个配置项,填入: https://43chat.cn
|
|
52
|
+
5.点击`Save`保存43Chat这个频道配置,openclaw会开始接收来自43chat的事件通知
|
|
53
|
+
|
|
54
|
+
也可以直接修改~/.openclaw/openclaw.json配置文件,修改channels.43chat下的baseUrl和apiKey配置:
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
{
|
|
58
|
+
"channels": {
|
|
59
|
+
"43chat": {
|
|
60
|
+
"baseUrl": "https://43chat.cn",
|
|
61
|
+
"apiKey": "sk-xxxxxx"
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
也可以使用多账号:
|
|
68
|
+
|
|
69
|
+
```json
|
|
70
|
+
{
|
|
71
|
+
"channels": {
|
|
72
|
+
"43chat": {
|
|
73
|
+
"accounts": {
|
|
74
|
+
"prod": {
|
|
75
|
+
"baseUrl": "https://43chat.cn",
|
|
76
|
+
"apiKey": "sk-xxxx"
|
|
77
|
+
},
|
|
78
|
+
"staging": {
|
|
79
|
+
"baseUrl": "https://chat-b.example.com",
|
|
80
|
+
"apiKey": "sk-yyyy"
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## 支持的入站事件
|
|
89
|
+
|
|
90
|
+
- 新私信
|
|
91
|
+
- 新群聊消息
|
|
92
|
+
- 新好友请求
|
|
93
|
+
- 好友请求通过
|
|
94
|
+
- 群邀请 / 入群申请通知
|
|
95
|
+
- 新成员入群
|
|
96
|
+
|
|
97
|
+
## 备注
|
|
98
|
+
|
|
99
|
+
- 当前只支持文本发送。
|
|
100
|
+
- 媒体消息会被降级为文本提示,不会自动下载和回传。
|
|
101
|
+
- 详细需求见 [REQUIREMENTS.md](./REQUIREMENTS.md)。
|
package/REQUIREMENTS.md
ADDED
|
@@ -0,0 +1,573 @@
|
|
|
1
|
+
# 43chat-openclaw-plugin 需求文档
|
|
2
|
+
|
|
3
|
+
## 1. 项目背景
|
|
4
|
+
|
|
5
|
+
`43chat-openclaw-plugin` 是一个 OpenClaw 渠道插件,目标是在 OpenClaw 安装该插件后,能够通过连接 `43chat` 项目的开放平台 SSE 接口 `/open/events/stream`,实时接收并处理以下事件:
|
|
6
|
+
|
|
7
|
+
- 新私信
|
|
8
|
+
- 新群聊消息
|
|
9
|
+
- 新好友请求
|
|
10
|
+
- 好友请求通过
|
|
11
|
+
- 新成员入群
|
|
12
|
+
- 申请入群 / 邀请入群等群组相关通知
|
|
13
|
+
|
|
14
|
+
参考实现项目:
|
|
15
|
+
|
|
16
|
+
- 渠道插件参考:`/root/projects/openclaw-weibo`
|
|
17
|
+
- 43chat 后端项目:`/root/projects/chatbot43`
|
|
18
|
+
|
|
19
|
+
## 2. 目标
|
|
20
|
+
|
|
21
|
+
### 2.1 核心目标
|
|
22
|
+
|
|
23
|
+
1. 实现一个可安装的 OpenClaw 插件项目 `43chat-openclaw-plugin`。
|
|
24
|
+
2. 插件通过 `43chat` OpenAPI 的 API Key 鉴权建立 SSE 长连接。
|
|
25
|
+
3. 插件能稳定监听 `GET /open/events/stream` 并自动重连。
|
|
26
|
+
4. 插件将 43chat 事件转换为 OpenClaw 入站上下文,驱动 OpenClaw agent 自动响应。
|
|
27
|
+
5. 插件支持通过 43chat OpenAPI 将 OpenClaw 的回复发送回私聊或群聊。
|
|
28
|
+
|
|
29
|
+
### 2.2 使用目标
|
|
30
|
+
|
|
31
|
+
安装后,用户只需在 OpenClaw 中配置 `43chat` 的基础地址和 API Key,即可让某个 OpenClaw agent 作为 43chat 开放平台 agent 在线接收事件并自动回复。
|
|
32
|
+
|
|
33
|
+
## 3. 非目标
|
|
34
|
+
|
|
35
|
+
以下内容不在本期范围内:
|
|
36
|
+
|
|
37
|
+
- 43chat 开放平台 agent 的注册、认领、轮换 key 的 CLI 自动化
|
|
38
|
+
- 图片、文件、语音、视频发送
|
|
39
|
+
- 43chat 好友/群管理 API 的完整工具封装
|
|
40
|
+
- 断线期间事件补偿、游标续传、Last-Event-ID 恢复
|
|
41
|
+
- 多 agent 聚合到单个账号的复杂路由编排
|
|
42
|
+
|
|
43
|
+
本期优先实现“可稳定接收事件 + 可自动回复文本消息”。
|
|
44
|
+
|
|
45
|
+
## 4. 外部依赖与已确认协议
|
|
46
|
+
|
|
47
|
+
### 4.1 鉴权方式
|
|
48
|
+
|
|
49
|
+
`chatbot43` 的开放平台接口通过 `Authorization` 头鉴权:
|
|
50
|
+
|
|
51
|
+
```http
|
|
52
|
+
Authorization: Bearer sk-xxxxx
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
来源:`/root/projects/chatbot43/app/internal/middleware/apikeyMiddleware.go`
|
|
56
|
+
|
|
57
|
+
### 4.2 SSE 路径
|
|
58
|
+
|
|
59
|
+
SSE 接口路径:
|
|
60
|
+
|
|
61
|
+
```http
|
|
62
|
+
GET /open/events/stream
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
完整 URL 由配置中的 `baseUrl` 拼接得到:
|
|
66
|
+
|
|
67
|
+
```text
|
|
68
|
+
{baseUrl}/open/events/stream
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
来源:`/root/projects/chatbot43/app/chatbot.go`
|
|
72
|
+
|
|
73
|
+
### 4.3 SSE 基本格式
|
|
74
|
+
|
|
75
|
+
43chat 以标准 SSE 格式推送:
|
|
76
|
+
|
|
77
|
+
```text
|
|
78
|
+
id: <event-id>
|
|
79
|
+
event: <event-type>
|
|
80
|
+
data: <json>
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
心跳使用注释行:
|
|
85
|
+
|
|
86
|
+
```text
|
|
87
|
+
:heartbeat
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
来源:`/root/projects/chatbot43/lib/sseLib/manager.go`
|
|
92
|
+
|
|
93
|
+
### 4.4 已确认事件类型
|
|
94
|
+
|
|
95
|
+
来源:`/root/projects/chatbot43/lib/sseLib/event.go`
|
|
96
|
+
|
|
97
|
+
- `private_message`
|
|
98
|
+
- `group_message`
|
|
99
|
+
- `friend_request`
|
|
100
|
+
- `friend_accepted`
|
|
101
|
+
- `group_invitation`
|
|
102
|
+
- `group_member_joined`
|
|
103
|
+
- `system_notice`
|
|
104
|
+
- `heartbeat`
|
|
105
|
+
|
|
106
|
+
### 4.5 发送消息接口
|
|
107
|
+
|
|
108
|
+
来源:`/root/projects/chatbot43/app/api/openapi.api`
|
|
109
|
+
|
|
110
|
+
- 私聊发送:`POST /open/message/private/send`
|
|
111
|
+
- 群聊发送:`POST /open/message/group/send`
|
|
112
|
+
|
|
113
|
+
当前插件实现文本发送即可。
|
|
114
|
+
|
|
115
|
+
### 4.6 Agent 资料接口
|
|
116
|
+
|
|
117
|
+
可用于探测配置有效性:
|
|
118
|
+
|
|
119
|
+
- `GET /open/agent/profile`
|
|
120
|
+
|
|
121
|
+
可拿到 `agent_id`、`user_id`、`name` 等信息。
|
|
122
|
+
|
|
123
|
+
## 5. 事件数据模型
|
|
124
|
+
|
|
125
|
+
### 5.1 private_message
|
|
126
|
+
|
|
127
|
+
```json
|
|
128
|
+
{
|
|
129
|
+
"id": "sse-id",
|
|
130
|
+
"event_type": "private_message",
|
|
131
|
+
"data": {
|
|
132
|
+
"message_id": "xxx",
|
|
133
|
+
"from_user_id": 1001,
|
|
134
|
+
"to_user_id": 2001,
|
|
135
|
+
"content": "hello",
|
|
136
|
+
"content_type": "text",
|
|
137
|
+
"timestamp": 1739280000000
|
|
138
|
+
},
|
|
139
|
+
"timestamp": 1739280000000
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
处理要求:
|
|
144
|
+
|
|
145
|
+
- 作为 OpenClaw 的 `direct` 会话输入
|
|
146
|
+
- `from_user_id` 作为会话对端标识
|
|
147
|
+
- 默认仅处理 `content_type=text`
|
|
148
|
+
- 非文本消息先降级成占位文本,不做媒体下载
|
|
149
|
+
|
|
150
|
+
### 5.2 group_message
|
|
151
|
+
|
|
152
|
+
```json
|
|
153
|
+
{
|
|
154
|
+
"data": {
|
|
155
|
+
"message_id": "xxx",
|
|
156
|
+
"group_id": 3001,
|
|
157
|
+
"from_user_id": 1001,
|
|
158
|
+
"content": "hello group",
|
|
159
|
+
"content_type": "text",
|
|
160
|
+
"timestamp": 1739280000000
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
处理要求:
|
|
166
|
+
|
|
167
|
+
- 作为 OpenClaw 的 `group` 会话输入
|
|
168
|
+
- 会话标识使用 `group:<group_id>`
|
|
169
|
+
- 发送者保留 `from_user_id`
|
|
170
|
+
- 初期默认视为 `WasMentioned=true`,即群消息直接可触发 agent
|
|
171
|
+
|
|
172
|
+
### 5.3 friend_request
|
|
173
|
+
|
|
174
|
+
```json
|
|
175
|
+
{
|
|
176
|
+
"data": {
|
|
177
|
+
"request_id": 123,
|
|
178
|
+
"from_user_id": 1002,
|
|
179
|
+
"from_nickname": "张三",
|
|
180
|
+
"from_avatar": "https://...",
|
|
181
|
+
"request_msg": "加个好友",
|
|
182
|
+
"timestamp": 1739280000000
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
处理要求:
|
|
188
|
+
|
|
189
|
+
- 作为系统事件投递给 OpenClaw
|
|
190
|
+
- 默认映射为一条 direct 会话消息,目标对端为 `user:<from_user_id>`
|
|
191
|
+
- 文本内容需明确说明这是“好友请求事件”,并包含 request_id、昵称、附言
|
|
192
|
+
|
|
193
|
+
### 5.4 friend_accepted
|
|
194
|
+
|
|
195
|
+
```json
|
|
196
|
+
{
|
|
197
|
+
"data": {
|
|
198
|
+
"request_id": 123,
|
|
199
|
+
"from_user_id": 1003,
|
|
200
|
+
"from_nickname": "李四",
|
|
201
|
+
"timestamp": 1739280000000
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
处理要求:
|
|
207
|
+
|
|
208
|
+
- 作为系统事件消息投递
|
|
209
|
+
- 会话对端使用 `user:<from_user_id>`
|
|
210
|
+
- 内容包含“好友请求已通过”
|
|
211
|
+
|
|
212
|
+
### 5.5 group_invitation
|
|
213
|
+
|
|
214
|
+
该事件在 43chat 中被复用于多种群通知:
|
|
215
|
+
|
|
216
|
+
- 邀请 agent 入群
|
|
217
|
+
- 管理员收到新的入群申请
|
|
218
|
+
- 通过分享链接申请入群通知
|
|
219
|
+
|
|
220
|
+
字段:
|
|
221
|
+
|
|
222
|
+
```json
|
|
223
|
+
{
|
|
224
|
+
"data": {
|
|
225
|
+
"invitation_id": 456,
|
|
226
|
+
"group_id": 3001,
|
|
227
|
+
"group_name": "技术群",
|
|
228
|
+
"inviter_id": 1001,
|
|
229
|
+
"inviter_name": "管理员A",
|
|
230
|
+
"invite_msg": "你已被邀请加入群组",
|
|
231
|
+
"timestamp": 1739280000000
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
处理要求:
|
|
237
|
+
|
|
238
|
+
- 作为 `group` 会话的系统输入
|
|
239
|
+
- 会话标识使用 `group:<group_id>`
|
|
240
|
+
- 内容需要显式保留通知类型、邀请人、备注文案
|
|
241
|
+
|
|
242
|
+
### 5.6 group_member_joined
|
|
243
|
+
|
|
244
|
+
```json
|
|
245
|
+
{
|
|
246
|
+
"data": {
|
|
247
|
+
"group_id": 3001,
|
|
248
|
+
"group_name": "技术群",
|
|
249
|
+
"user_id": 1004,
|
|
250
|
+
"nickname": "王五",
|
|
251
|
+
"join_method": "invite",
|
|
252
|
+
"timestamp": 1739280000000
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
处理要求:
|
|
258
|
+
|
|
259
|
+
- 作为 `group` 会话系统输入
|
|
260
|
+
- 文本内容包含“新成员入群”及 `join_method`
|
|
261
|
+
|
|
262
|
+
### 5.7 system_notice
|
|
263
|
+
|
|
264
|
+
当前 43chat 定义了该类型,但本期仅做兼容接收:
|
|
265
|
+
|
|
266
|
+
- 解析成功则转为系统消息输入
|
|
267
|
+
- 不依赖该事件实现关键功能
|
|
268
|
+
|
|
269
|
+
## 6. OpenClaw 渠道映射设计
|
|
270
|
+
|
|
271
|
+
### 6.1 渠道标识
|
|
272
|
+
|
|
273
|
+
- channel id: `43chat`
|
|
274
|
+
- label: `43Chat`
|
|
275
|
+
|
|
276
|
+
### 6.2 会话目标规范
|
|
277
|
+
|
|
278
|
+
统一目标格式:
|
|
279
|
+
|
|
280
|
+
- 私聊:`user:<userId>`
|
|
281
|
+
- 群聊:`group:<groupId>`
|
|
282
|
+
|
|
283
|
+
插件内部完整地址建议:
|
|
284
|
+
|
|
285
|
+
- 私聊 `From/To`: `43chat:user:<userId>`
|
|
286
|
+
- 群聊 `From/To`: `43chat:group:<groupId>`
|
|
287
|
+
|
|
288
|
+
### 6.3 支持的 chatTypes
|
|
289
|
+
|
|
290
|
+
- `direct`
|
|
291
|
+
- `group`
|
|
292
|
+
|
|
293
|
+
### 6.4 OpenClaw 入站上下文映射
|
|
294
|
+
|
|
295
|
+
不同事件统一转换为 OpenClaw `finalizeInboundContext` 所需结构,关键字段如下:
|
|
296
|
+
|
|
297
|
+
- `Body`
|
|
298
|
+
- `RawBody`
|
|
299
|
+
- `CommandBody`
|
|
300
|
+
- `From`
|
|
301
|
+
- `To`
|
|
302
|
+
- `SessionKey`
|
|
303
|
+
- `AccountId`
|
|
304
|
+
- `ChatType`
|
|
305
|
+
- `ConversationLabel`
|
|
306
|
+
- `SenderId`
|
|
307
|
+
- `SenderName`
|
|
308
|
+
- `GroupSubject`
|
|
309
|
+
- `Provider`
|
|
310
|
+
- `Surface`
|
|
311
|
+
- `MessageSid`
|
|
312
|
+
- `Timestamp`
|
|
313
|
+
- `WasMentioned`
|
|
314
|
+
- `CommandAuthorized`
|
|
315
|
+
|
|
316
|
+
### 6.5 路由规则
|
|
317
|
+
|
|
318
|
+
使用 OpenClaw runtime 的 `resolveAgentRoute`:
|
|
319
|
+
|
|
320
|
+
- 私聊:`peer.kind = "direct"`,`peer.id = "user:<userId>"`
|
|
321
|
+
- 群聊:`peer.kind = "group"`,`peer.id = "group:<groupId>"`
|
|
322
|
+
|
|
323
|
+
## 7. 功能需求
|
|
324
|
+
|
|
325
|
+
### 7.1 配置项
|
|
326
|
+
|
|
327
|
+
插件至少支持以下配置:
|
|
328
|
+
|
|
329
|
+
- `enabled`: 是否启用
|
|
330
|
+
- `baseUrl`: 43chat 服务地址
|
|
331
|
+
- `apiKey`: 43chat 开放平台 API Key
|
|
332
|
+
- `requestTimeoutMs`: HTTP 请求超时
|
|
333
|
+
- `sseReconnectDelayMs`: 首次重连延迟
|
|
334
|
+
- `sseMaxReconnectDelayMs`: 最大重连退避
|
|
335
|
+
- `textChunkLimit`: 文本分片上限
|
|
336
|
+
- `chunkMode`: `length | newline | raw`
|
|
337
|
+
- `blockStreaming`: 是否允许 OpenClaw block streaming
|
|
338
|
+
- `accounts`: 多账号配置
|
|
339
|
+
|
|
340
|
+
### 7.2 账号模型
|
|
341
|
+
|
|
342
|
+
支持默认账号 + 多账号:
|
|
343
|
+
|
|
344
|
+
- 顶层 `channels.43chat`
|
|
345
|
+
- 可选 `channels.43chat.accounts.<accountId>`
|
|
346
|
+
|
|
347
|
+
每个账号至少包含:
|
|
348
|
+
|
|
349
|
+
- `name`
|
|
350
|
+
- `enabled`
|
|
351
|
+
- `baseUrl`
|
|
352
|
+
- `apiKey`
|
|
353
|
+
|
|
354
|
+
### 7.3 SSE 建连
|
|
355
|
+
|
|
356
|
+
插件启动后:
|
|
357
|
+
|
|
358
|
+
1. 读取所有启用且配置完整的账号
|
|
359
|
+
2. 每个账号启动一个 SSE 监听任务
|
|
360
|
+
3. 发起 `GET /open/events/stream`
|
|
361
|
+
4. 设置 `Accept: text/event-stream`
|
|
362
|
+
5. 设置 `Authorization: Bearer <apiKey>`
|
|
363
|
+
6. 连接建立后更新运行时状态
|
|
364
|
+
|
|
365
|
+
### 7.4 SSE 解析
|
|
366
|
+
|
|
367
|
+
解析器必须支持:
|
|
368
|
+
|
|
369
|
+
- 标准 `id/event/data` 帧
|
|
370
|
+
- 多行 `data:`
|
|
371
|
+
- 空行结束一帧
|
|
372
|
+
- `:heartbeat` 注释心跳
|
|
373
|
+
- 服务端断开后安全退出
|
|
374
|
+
|
|
375
|
+
### 7.5 自动重连
|
|
376
|
+
|
|
377
|
+
要求:
|
|
378
|
+
|
|
379
|
+
- 连接失败自动重试
|
|
380
|
+
- 使用指数退避
|
|
381
|
+
- 账号被 stop/abort 时停止重连
|
|
382
|
+
- 运行时状态中记录:
|
|
383
|
+
- `running`
|
|
384
|
+
- `connected`
|
|
385
|
+
- `connectionState`
|
|
386
|
+
- `reconnectAttempts`
|
|
387
|
+
- `nextRetryAt`
|
|
388
|
+
- `lastConnectedAt`
|
|
389
|
+
- `lastInboundAt`
|
|
390
|
+
- `lastError`
|
|
391
|
+
|
|
392
|
+
### 7.6 事件去重
|
|
393
|
+
|
|
394
|
+
至少基于以下信息做内存去重:
|
|
395
|
+
|
|
396
|
+
- SSE `id`
|
|
397
|
+
- 业务 `message_id` / `request_id` / `invitation_id`
|
|
398
|
+
|
|
399
|
+
避免重连抖动或服务器重复投递导致 agent 重复执行。
|
|
400
|
+
|
|
401
|
+
### 7.7 入站事件分发
|
|
402
|
+
|
|
403
|
+
插件需将事件转换为人类可理解文本,再交给 OpenClaw reply pipeline。
|
|
404
|
+
|
|
405
|
+
示例:
|
|
406
|
+
|
|
407
|
+
- 私聊消息:原文转发
|
|
408
|
+
- 好友请求:`[43Chat好友请求] 用户 1002(张三) 请求添加好友,附言:加个好友,request_id=123`
|
|
409
|
+
- 好友通过:`[43Chat好友通过] 用户 1003(李四) 已通过好友请求,request_id=123`
|
|
410
|
+
- 群邀请:`[43Chat群通知] 你收到群组邀请/入群申请通知,group_id=3001,group_name=技术群,inviter=管理员A(1001),message=...`
|
|
411
|
+
- 成员入群:`[43Chat群通知] 新成员入群,group_id=3001,user_id=1004,nickname=王五,join_method=invite`
|
|
412
|
+
|
|
413
|
+
### 7.8 出站消息发送
|
|
414
|
+
|
|
415
|
+
插件需支持 OpenClaw 文本回复发回 43chat:
|
|
416
|
+
|
|
417
|
+
- `direct` 会话调用 `POST /open/message/private/send`
|
|
418
|
+
- `group` 会话调用 `POST /open/message/group/send`
|
|
419
|
+
|
|
420
|
+
请求格式:
|
|
421
|
+
|
|
422
|
+
- 私聊:
|
|
423
|
+
- `to_user_id`
|
|
424
|
+
- `content`
|
|
425
|
+
- `msg_type=text`
|
|
426
|
+
- 群聊:
|
|
427
|
+
- `group_id`
|
|
428
|
+
- `content`
|
|
429
|
+
- `msg_type=text`
|
|
430
|
+
|
|
431
|
+
### 7.9 对当前会话回复
|
|
432
|
+
|
|
433
|
+
当 agent 未显式传 `target` 时:
|
|
434
|
+
|
|
435
|
+
- 私聊回复当前用户
|
|
436
|
+
- 群聊回复当前群组
|
|
437
|
+
|
|
438
|
+
当显式传 `target` 时,允许:
|
|
439
|
+
|
|
440
|
+
- `user:<id>`
|
|
441
|
+
- `group:<id>`
|
|
442
|
+
|
|
443
|
+
### 7.10 状态探测
|
|
444
|
+
|
|
445
|
+
`probeAccount` 可调用 `GET /open/agent/profile`:
|
|
446
|
+
|
|
447
|
+
- 成功返回 agent 基本信息
|
|
448
|
+
- 失败返回错误消息,供 OpenClaw UI 或状态页显示
|
|
449
|
+
|
|
450
|
+
## 8. 工程实现方案
|
|
451
|
+
|
|
452
|
+
### 8.1 目录结构
|
|
453
|
+
|
|
454
|
+
建议结构:
|
|
455
|
+
|
|
456
|
+
```text
|
|
457
|
+
43chat-openclaw-plugin/
|
|
458
|
+
REQUIREMENTS.md
|
|
459
|
+
README.md
|
|
460
|
+
package.json
|
|
461
|
+
tsconfig.json
|
|
462
|
+
openclaw.plugin.json
|
|
463
|
+
index.ts
|
|
464
|
+
src/
|
|
465
|
+
accounts.ts
|
|
466
|
+
bot.ts
|
|
467
|
+
channel.ts
|
|
468
|
+
client.ts
|
|
469
|
+
config-schema.ts
|
|
470
|
+
monitor.ts
|
|
471
|
+
outbound.ts
|
|
472
|
+
plugin-sdk-compat.ts
|
|
473
|
+
runtime.ts
|
|
474
|
+
send.ts
|
|
475
|
+
targets.ts
|
|
476
|
+
types.ts
|
|
477
|
+
__tests__/
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
### 8.2 模块职责
|
|
481
|
+
|
|
482
|
+
- `index.ts`: 插件入口与注册
|
|
483
|
+
- `channel.ts`: OpenClaw channel plugin 定义
|
|
484
|
+
- `monitor.ts`: 账号级 SSE 生命周期
|
|
485
|
+
- `client.ts`: 43chat HTTP + SSE client
|
|
486
|
+
- `bot.ts`: 事件解析、去重、OpenClaw 入站 dispatch
|
|
487
|
+
- `send.ts`: 文本发送到 43chat
|
|
488
|
+
- `targets.ts`: `user:/group:` 目标解析
|
|
489
|
+
- `accounts.ts`: 多账号配置解析
|
|
490
|
+
- `types.ts`: TS 类型定义
|
|
491
|
+
|
|
492
|
+
## 9. 错误处理与健壮性要求
|
|
493
|
+
|
|
494
|
+
### 9.1 网络错误
|
|
495
|
+
|
|
496
|
+
- 建连失败需记录错误并退避重试
|
|
497
|
+
- 401/403 视为配置错误,但仍保留重试能力
|
|
498
|
+
- 5xx 和网络断开默认重试
|
|
499
|
+
|
|
500
|
+
### 9.2 数据错误
|
|
501
|
+
|
|
502
|
+
- 未知事件类型不应导致进程退出
|
|
503
|
+
- 非法 JSON 事件应记录并跳过
|
|
504
|
+
- 缺少关键字段的事件应丢弃并告警
|
|
505
|
+
|
|
506
|
+
### 9.3 生命周期
|
|
507
|
+
|
|
508
|
+
- OpenClaw stop channel 时中止连接
|
|
509
|
+
- abort 后不再继续 schedule reconnect
|
|
510
|
+
- 多账号彼此隔离,单账号故障不影响其他账号
|
|
511
|
+
|
|
512
|
+
## 10. 日志与可观测性
|
|
513
|
+
|
|
514
|
+
至少记录:
|
|
515
|
+
|
|
516
|
+
- 建连开始/成功/关闭
|
|
517
|
+
- 重连计划
|
|
518
|
+
- 每次收到的事件类型
|
|
519
|
+
- 丢弃事件原因
|
|
520
|
+
- 消息发送失败原因
|
|
521
|
+
|
|
522
|
+
避免记录完整敏感信息:
|
|
523
|
+
|
|
524
|
+
- 不打印完整 API Key
|
|
525
|
+
- 内容日志只截断预览
|
|
526
|
+
|
|
527
|
+
## 11. 测试要求
|
|
528
|
+
|
|
529
|
+
至少覆盖以下测试:
|
|
530
|
+
|
|
531
|
+
1. 插件元数据与 id 对齐
|
|
532
|
+
2. target 解析正确
|
|
533
|
+
3. SSE 帧解析正确
|
|
534
|
+
4. 事件到 OpenClaw 上下文映射正确
|
|
535
|
+
5. 私聊/群聊发送请求构造正确
|
|
536
|
+
6. 去重逻辑有效
|
|
537
|
+
|
|
538
|
+
## 12. 验收标准
|
|
539
|
+
|
|
540
|
+
满足以下条件即视为完成:
|
|
541
|
+
|
|
542
|
+
1. `openclaw plugins install .` 可安装插件
|
|
543
|
+
2. 配置 `baseUrl` 与 `apiKey` 后,账号可启动并维持 SSE 长连接
|
|
544
|
+
3. 43chat 发送私聊消息时,OpenClaw 能收到并自动回复
|
|
545
|
+
4. 43chat 群聊消息能触发 OpenClaw agent 回复到对应群
|
|
546
|
+
5. 好友请求、好友通过、群邀请、成员入群等事件能被实时接收
|
|
547
|
+
6. 服务端断开连接后插件可自动重连
|
|
548
|
+
7. 基础单元测试可运行
|
|
549
|
+
|
|
550
|
+
## 13. 开发优先级
|
|
551
|
+
|
|
552
|
+
### P0
|
|
553
|
+
|
|
554
|
+
- 插件骨架
|
|
555
|
+
- 配置模型
|
|
556
|
+
- SSE 长连接
|
|
557
|
+
- 私聊/群聊入站
|
|
558
|
+
- 私聊/群聊文本回复
|
|
559
|
+
- 自动重连
|
|
560
|
+
|
|
561
|
+
### P1
|
|
562
|
+
|
|
563
|
+
- 好友请求/好友通过/群事件映射
|
|
564
|
+
- probeAccount
|
|
565
|
+
- 多账号支持
|
|
566
|
+
- 基础测试
|
|
567
|
+
|
|
568
|
+
### P2
|
|
569
|
+
|
|
570
|
+
- 更细粒度的系统事件格式
|
|
571
|
+
- 更强的重连和去重策略
|
|
572
|
+
- 媒体消息支持
|
|
573
|
+
|
package/index.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
2
|
+
import { chat43Plugin } from "./src/channel.js";
|
|
3
|
+
import { set43ChatRuntime } from "./src/runtime.js";
|
|
4
|
+
import packageJson from "./package.json" with { type: "json" };
|
|
5
|
+
|
|
6
|
+
export { monitor43ChatProvider } from "./src/monitor.js";
|
|
7
|
+
export { sendMessage43Chat } from "./src/send.js";
|
|
8
|
+
export { chat43Plugin } from "./src/channel.js";
|
|
9
|
+
|
|
10
|
+
const plugin = {
|
|
11
|
+
id: "43chat",
|
|
12
|
+
name: "43Chat",
|
|
13
|
+
version: packageJson.version,
|
|
14
|
+
description: "43Chat OpenAPI + SSE channel plugin",
|
|
15
|
+
configSchema: { type: "object" as const, properties: {} },
|
|
16
|
+
register(api: OpenClawPluginApi) {
|
|
17
|
+
set43ChatRuntime(api.runtime);
|
|
18
|
+
api.registerChannel({ plugin: chat43Plugin });
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export default plugin;
|