@xmoxmo/bncr 0.0.2 → 0.0.4
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 +45 -315
- package/index.ts +24 -0
- package/package.json +1 -1
- package/src/channel.ts +1078 -79
- package/LICENSE +0 -21
package/README.md
CHANGED
|
@@ -1,350 +1,80 @@
|
|
|
1
|
-
# bncr
|
|
1
|
+
# bncr
|
|
2
2
|
|
|
3
|
-
OpenClaw 的 Bncr
|
|
3
|
+
OpenClaw 的 Bncr 频道插件(`channelId=bncr`)。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
作用很简单:把 **Bncr / 无界客户端** 接到 **OpenClaw 网关**,用于消息双向通信与媒体/文件传输。
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## 安装
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
- **Bridge Version**:`2`
|
|
13
|
-
- **出站事件名**:`bncr.push`
|
|
14
|
-
- **出站模式**:`push-only`(不依赖 pull 轮询)
|
|
15
|
-
- **活动心跳方法**:`bncr.activity`
|
|
11
|
+
### OpenClaw 侧
|
|
16
12
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
## 2. 工作模式(重点)
|
|
20
|
-
|
|
21
|
-
当前是 **push-only**:
|
|
22
|
-
|
|
23
|
-
- Bncr 在线:OpenClaw 通过 WS `event=bncr.push` 直接下发回复。
|
|
24
|
-
- Bncr 离线:消息进入 outbox;重连后自动冲队列。
|
|
25
|
-
- `bncr.activity` 仅用于在线保活,不承载拉取。
|
|
26
|
-
- `bncr.ack` 兼容保留,当前不是必需链路(fire-and-forget)。
|
|
27
|
-
|
|
28
|
-
> 结论:客户端最小实现只需两件事:
|
|
29
|
-
> 1) 发 `bncr.inbound`;2) 监听 `bncr.push`。
|
|
13
|
+
在 OpenClaw 上执行:
|
|
30
14
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
严格格式:
|
|
36
|
-
|
|
37
|
-
```text
|
|
38
|
-
agent:main:bncr:direct:<hexScope>
|
|
15
|
+
```bash
|
|
16
|
+
openclaw plugins install @xmoxmo/bncr
|
|
17
|
+
openclaw plugins enable bncr
|
|
18
|
+
openclaw gateway restart
|
|
39
19
|
```
|
|
40
20
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
- `<hexScope>` = `platform:groupId:userId` 的 UTF-8 hex(小写)。
|
|
44
|
-
- 仅允许 `0-9a-f` 且长度为偶数。
|
|
45
|
-
- 旧格式(如 `...:<hexScope>:0`)不再作为标准形态。
|
|
21
|
+
### Bncr / 无界侧
|
|
46
22
|
|
|
47
|
-
|
|
23
|
+
安装:
|
|
48
24
|
|
|
49
|
-
|
|
50
|
-
scope = qq:0:888888
|
|
51
|
-
hexScope = 71713a303a383838383838
|
|
52
|
-
sessionKey= agent:main:bncr:direct:71713a303a383838383838
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
---
|
|
25
|
+
- `openclawclient.js`
|
|
56
26
|
|
|
57
|
-
|
|
27
|
+
然后完成客户端配置,至少包括:
|
|
58
28
|
|
|
59
|
-
|
|
29
|
+
- OpenClaw 地址
|
|
30
|
+
- 端口
|
|
31
|
+
- Token
|
|
32
|
+
- 连接相关参数
|
|
60
33
|
|
|
61
|
-
|
|
62
|
-
- `bncr.inbound`
|
|
63
|
-
- `bncr.activity`
|
|
64
|
-
- `bncr.ack`
|
|
34
|
+
配置完成后,让客户端成功连到 OpenClaw 网关即可。
|
|
65
35
|
|
|
66
36
|
---
|
|
67
37
|
|
|
68
|
-
##
|
|
69
|
-
|
|
70
|
-
### Step A:建立 WS 并发送 `bncr.connect`
|
|
71
|
-
|
|
72
|
-
请求示例:
|
|
38
|
+
## 支持能力
|
|
73
39
|
|
|
74
|
-
|
|
75
|
-
{
|
|
76
|
-
"type": "req",
|
|
77
|
-
"id": "c1",
|
|
78
|
-
"method": "bncr.connect",
|
|
79
|
-
"params": {
|
|
80
|
-
"accountId": "Primary",
|
|
81
|
-
"clientId": "bncr-client-1"
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
响应示例:
|
|
40
|
+
### 支持内容
|
|
87
41
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
"channel": "bncr",
|
|
95
|
-
"accountId": "Primary",
|
|
96
|
-
"bridgeVersion": 2,
|
|
97
|
-
"pushEvent": "bncr.push",
|
|
98
|
-
"online": true,
|
|
99
|
-
"isPrimary": true,
|
|
100
|
-
"activeConnections": 1,
|
|
101
|
-
"pending": 0,
|
|
102
|
-
"deadLetter": 0,
|
|
103
|
-
"now": 1772476800000
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
```
|
|
42
|
+
- 文本
|
|
43
|
+
- 图片
|
|
44
|
+
- 视频
|
|
45
|
+
- 语音
|
|
46
|
+
- 音频
|
|
47
|
+
- 文件
|
|
107
48
|
|
|
108
|
-
|
|
49
|
+
### 其它特性
|
|
109
50
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
{
|
|
116
|
-
"type": "req",
|
|
117
|
-
"id": "i1",
|
|
118
|
-
"method": "bncr.inbound",
|
|
119
|
-
"params": {
|
|
120
|
-
"accountId": "Primary",
|
|
121
|
-
"platform": "qq",
|
|
122
|
-
"groupId": "0",
|
|
123
|
-
"userId": "888888",
|
|
124
|
-
"sessionKey": "agent:main:bncr:direct:71713a303a383838383838",
|
|
125
|
-
"msgId": "msg-1001",
|
|
126
|
-
"type": "text",
|
|
127
|
-
"msg": "你好"
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
媒体请求示例(字段是 `base64`):
|
|
133
|
-
|
|
134
|
-
```json
|
|
135
|
-
{
|
|
136
|
-
"type": "req",
|
|
137
|
-
"id": "i2",
|
|
138
|
-
"method": "bncr.inbound",
|
|
139
|
-
"params": {
|
|
140
|
-
"accountId": "Primary",
|
|
141
|
-
"platform": "qq",
|
|
142
|
-
"groupId": "0",
|
|
143
|
-
"userId": "888888",
|
|
144
|
-
"sessionKey": "agent:main:bncr:direct:71713a303a383838383838",
|
|
145
|
-
"msgId": "msg-1002",
|
|
146
|
-
"type": "image/png",
|
|
147
|
-
"msg": "",
|
|
148
|
-
"base64": "<BASE64_PAYLOAD>",
|
|
149
|
-
"mimeType": "image/png",
|
|
150
|
-
"fileName": "demo.png"
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
响应示例:
|
|
156
|
-
|
|
157
|
-
```json
|
|
158
|
-
{
|
|
159
|
-
"type": "res",
|
|
160
|
-
"id": "i1",
|
|
161
|
-
"ok": true,
|
|
162
|
-
"result": {
|
|
163
|
-
"accepted": true,
|
|
164
|
-
"accountId": "Primary",
|
|
165
|
-
"sessionKey": "agent:main:bncr:direct:71713a303a383838383838",
|
|
166
|
-
"msgId": "msg-1001",
|
|
167
|
-
"taskKey": null
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
> `bncr.inbound` 先快速 ACK,再异步处理,最终回复经 `bncr.push` 回推。
|
|
173
|
-
|
|
174
|
-
### Step C:消费 `bncr.push`
|
|
175
|
-
|
|
176
|
-
事件示例:
|
|
177
|
-
|
|
178
|
-
```json
|
|
179
|
-
{
|
|
180
|
-
"type": "event",
|
|
181
|
-
"event": "bncr.push",
|
|
182
|
-
"payload": {
|
|
183
|
-
"type": "message.outbound",
|
|
184
|
-
"messageId": "3f8b1f9b-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
|
|
185
|
-
"idempotencyKey": "3f8b1f9b-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
|
|
186
|
-
"sessionKey": "agent:main:bncr:direct:71713a303a383838383838",
|
|
187
|
-
"message": {
|
|
188
|
-
"platform": "qq",
|
|
189
|
-
"groupId": "0",
|
|
190
|
-
"userId": "888888",
|
|
191
|
-
"type": "text",
|
|
192
|
-
"msg": "收到,已处理。",
|
|
193
|
-
"path": "",
|
|
194
|
-
"base64": "",
|
|
195
|
-
"fileName": ""
|
|
196
|
-
},
|
|
197
|
-
"ts": 1772476801234
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
```
|
|
51
|
+
- 下行推送
|
|
52
|
+
- 离线消息自动排队
|
|
53
|
+
- 重连后继续发送
|
|
54
|
+
- 支持诊断信息
|
|
55
|
+
- 支持文件互传
|
|
201
56
|
|
|
202
57
|
---
|
|
203
58
|
|
|
204
|
-
##
|
|
205
|
-
|
|
206
|
-
### 6.1 Bncr -> OpenClaw(`bncr.inbound`)
|
|
207
|
-
|
|
208
|
-
常用字段:
|
|
209
|
-
|
|
210
|
-
- `accountId`:可选(默认 `Primary`)
|
|
211
|
-
- `platform`:必填
|
|
212
|
-
- `groupId`:可选,默认 `"0"`(私聊)
|
|
213
|
-
- `userId`:建议填写(私聊/群聊都建议带上)
|
|
214
|
-
- `sessionKey`:可选,建议传严格 sessionKey(见第 3 节)
|
|
215
|
-
- `msgId`:建议传(便于短窗口去重)
|
|
216
|
-
- `type`:`text/image/video/file/...`
|
|
217
|
-
- `msg`:文本
|
|
218
|
-
- `base64`:媒体 base64
|
|
219
|
-
- `mimeType` / `fileName`:媒体元数据(可选)
|
|
220
|
-
|
|
221
|
-
校验失败常见错误:
|
|
222
|
-
|
|
223
|
-
- `platform/groupId/userId required`
|
|
224
|
-
|
|
225
|
-
#### 6.1.1 openclawclient.js(发送端)对齐说明
|
|
226
|
-
|
|
227
|
-
基于你当前附件版本(`openclawclient` 注释版本 `0.0.2`)核对结果:
|
|
59
|
+
## 安装后如何确认成功
|
|
228
60
|
|
|
229
|
-
|
|
230
|
-
- 文本消息使用 `msg`,与当前插件读取一致。
|
|
231
|
-
- 媒体字段使用 `base64`(可带 `mimeType/fileName`),与当前插件读取一致。
|
|
232
|
-
- 默认账号建议使用 `Primary`,并与网关账户 ID 保持大小写一致。
|
|
61
|
+
可以通过以下方式检查:
|
|
233
62
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
- `messageId`
|
|
239
|
-
- `idempotencyKey`(当前等于 `messageId`)
|
|
240
|
-
- `sessionKey`
|
|
241
|
-
- `message.platform/groupId/userId`
|
|
242
|
-
- `message.type/msg/path/base64/fileName`
|
|
243
|
-
- `ts`
|
|
244
|
-
|
|
245
|
-
说明:
|
|
246
|
-
|
|
247
|
-
- 主类型固定为 `type="message.outbound"`。
|
|
248
|
-
- 仅输出嵌套结构 `message.{...}`,不再输出平铺兼容字段。
|
|
249
|
-
- 不附带 webchat 的 `stream/state/data` 语义字段。
|
|
250
|
-
|
|
251
|
-
---
|
|
252
|
-
|
|
253
|
-
## 7. `message.send(channel=bncr)` 目标解析规则(重要)
|
|
254
|
-
|
|
255
|
-
插件发送目标支持三种输入:
|
|
256
|
-
|
|
257
|
-
1. 严格 `sessionKey`
|
|
258
|
-
2. `platform:groupId:userId`
|
|
259
|
-
3. `Bncr-platform:groupId:userId`
|
|
260
|
-
|
|
261
|
-
但发送前会做**反查校验**:
|
|
262
|
-
|
|
263
|
-
- 必须在已知会话路由里反查到真实 `sessionKey` 才会发送。
|
|
264
|
-
- 禁止拼凑 key 直接发;查不到会报:`target not found in known sessions`。
|
|
265
|
-
|
|
266
|
-
---
|
|
267
|
-
|
|
268
|
-
## 8. 重试与可靠性
|
|
269
|
-
|
|
270
|
-
- 离线入队 + 重连自动冲队列。
|
|
271
|
-
- 指数退避:`1s,2s,4s,8s...`
|
|
272
|
-
- 最大重试次数:`10`
|
|
273
|
-
- 超限进入 dead-letter。
|
|
274
|
-
|
|
275
|
-
---
|
|
276
|
-
|
|
277
|
-
## 9. 状态判定与观测
|
|
278
|
-
|
|
279
|
-
- 实际链路在线:`linked`
|
|
280
|
-
- 已配置但离线:`configured`
|
|
281
|
-
- 账户卡片中离线模式会显示 `Status`(展示口径)
|
|
282
|
-
|
|
283
|
-
常用状态字段:
|
|
284
|
-
|
|
285
|
-
- `pending`
|
|
286
|
-
- `deadLetter`
|
|
287
|
-
- `lastSessionKey`
|
|
288
|
-
- `lastSessionScope`(`Bncr-platform:group:user`)
|
|
289
|
-
- `lastSessionAt`
|
|
290
|
-
- `lastActivityAt`
|
|
291
|
-
- `lastInboundAt`
|
|
292
|
-
- `lastOutboundAt`
|
|
293
|
-
|
|
294
|
-
> 已知现象:`openclaw status` 顶层与 `status --deep` 在个别版本可能出现口径不一致;排障时优先看 `status --deep` 的 Health。
|
|
295
|
-
|
|
296
|
-
---
|
|
297
|
-
|
|
298
|
-
## 10. 兼容接口说明
|
|
299
|
-
|
|
300
|
-
### `bncr.activity`
|
|
301
|
-
|
|
302
|
-
用于活动保活,建议节流(例如 60s 一次)。
|
|
303
|
-
|
|
304
|
-
请求示例:
|
|
305
|
-
|
|
306
|
-
```json
|
|
307
|
-
{
|
|
308
|
-
"type": "req",
|
|
309
|
-
"id": "a1",
|
|
310
|
-
"method": "bncr.activity",
|
|
311
|
-
"params": {
|
|
312
|
-
"accountId": "Primary",
|
|
313
|
-
"clientId": "bncr-client-1",
|
|
314
|
-
"reason": "heartbeat"
|
|
315
|
-
}
|
|
316
|
-
}
|
|
63
|
+
```bash
|
|
64
|
+
openclaw gateway status
|
|
65
|
+
openclaw health --json
|
|
317
66
|
```
|
|
318
67
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
### `bncr.ack`
|
|
322
|
-
|
|
323
|
-
可调用,但当前模式下不是必需链路。
|
|
324
|
-
|
|
325
|
-
---
|
|
326
|
-
|
|
327
|
-
## 11. FAQ
|
|
328
|
-
|
|
329
|
-
### Q1:为什么看不到回复?
|
|
330
|
-
|
|
331
|
-
1. 先确认 `bncr.connect` 成功。
|
|
332
|
-
2. 客户端确认监听的是 `bncr.push`。
|
|
333
|
-
3. `sessionKey` 是否符合严格格式。
|
|
334
|
-
4. 若用 `message.send`,目标是否能反查到已知会话。
|
|
335
|
-
|
|
336
|
-
### Q2:为什么不需要 `bncr.pull`?
|
|
337
|
-
|
|
338
|
-
因为当前是 push-only,统一走 `bncr.push`。
|
|
68
|
+
重点看:
|
|
339
69
|
|
|
340
|
-
|
|
70
|
+
- 网关是否正常运行
|
|
71
|
+
- bncr 是否已经 `linked`
|
|
72
|
+
- 是否存在异常 pending / deadLetter
|
|
341
73
|
|
|
342
|
-
|
|
343
|
-
- 出站按 `idempotencyKey` 幂等处理。
|
|
344
|
-
- 客户端侧建议只消费 `message.outbound` 主链路。
|
|
74
|
+
如果 bncr 已成功连上,一般就说明插件安装和基础链路已经正常。
|
|
345
75
|
|
|
346
76
|
---
|
|
347
77
|
|
|
348
|
-
##
|
|
78
|
+
## 说明
|
|
349
79
|
|
|
350
|
-
|
|
80
|
+
如果你接触过旧版本,请以当前 README 和当前代码为准。
|
package/index.ts
CHANGED
|
@@ -37,6 +37,30 @@ const plugin = {
|
|
|
37
37
|
"bncr.ack",
|
|
38
38
|
(opts: GatewayRequestHandlerOptions) => bridge.handleAck(opts),
|
|
39
39
|
);
|
|
40
|
+
api.registerGatewayMethod(
|
|
41
|
+
"bncr.diagnostics",
|
|
42
|
+
(opts: GatewayRequestHandlerOptions) => bridge.handleDiagnostics(opts),
|
|
43
|
+
);
|
|
44
|
+
api.registerGatewayMethod(
|
|
45
|
+
"bncr.file.init",
|
|
46
|
+
(opts: GatewayRequestHandlerOptions) => bridge.handleFileInit(opts),
|
|
47
|
+
);
|
|
48
|
+
api.registerGatewayMethod(
|
|
49
|
+
"bncr.file.chunk",
|
|
50
|
+
(opts: GatewayRequestHandlerOptions) => bridge.handleFileChunk(opts),
|
|
51
|
+
);
|
|
52
|
+
api.registerGatewayMethod(
|
|
53
|
+
"bncr.file.complete",
|
|
54
|
+
(opts: GatewayRequestHandlerOptions) => bridge.handleFileComplete(opts),
|
|
55
|
+
);
|
|
56
|
+
api.registerGatewayMethod(
|
|
57
|
+
"bncr.file.abort",
|
|
58
|
+
(opts: GatewayRequestHandlerOptions) => bridge.handleFileAbort(opts),
|
|
59
|
+
);
|
|
60
|
+
api.registerGatewayMethod(
|
|
61
|
+
"bncr.file.ack",
|
|
62
|
+
(opts: GatewayRequestHandlerOptions) => bridge.handleFileAck(opts),
|
|
63
|
+
);
|
|
40
64
|
},
|
|
41
65
|
};
|
|
42
66
|
|