@xmoxmo/bncr 0.0.2 → 0.0.3
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 +106 -62
- package/index.ts +24 -0
- package/package.json +1 -1
- package/src/channel.ts +1017 -41
package/README.md
CHANGED
|
@@ -13,6 +13,13 @@ OpenClaw 的 Bncr WebSocket Bridge 频道插件(`channelId=bncr`)。
|
|
|
13
13
|
- **出站事件名**:`bncr.push`
|
|
14
14
|
- **出站模式**:`push-only`(不依赖 pull 轮询)
|
|
15
15
|
- **活动心跳方法**:`bncr.activity`
|
|
16
|
+
- **诊断方法**:`bncr.diagnostics`
|
|
17
|
+
- **文件互传方法(V1)**:
|
|
18
|
+
- `bncr.file.init`
|
|
19
|
+
- `bncr.file.chunk`
|
|
20
|
+
- `bncr.file.complete`
|
|
21
|
+
- `bncr.file.abort`
|
|
22
|
+
- `bncr.file.ack`
|
|
16
23
|
|
|
17
24
|
---
|
|
18
25
|
|
|
@@ -23,7 +30,7 @@ OpenClaw 的 Bncr WebSocket Bridge 频道插件(`channelId=bncr`)。
|
|
|
23
30
|
- Bncr 在线:OpenClaw 通过 WS `event=bncr.push` 直接下发回复。
|
|
24
31
|
- Bncr 离线:消息进入 outbox;重连后自动冲队列。
|
|
25
32
|
- `bncr.activity` 仅用于在线保活,不承载拉取。
|
|
26
|
-
- `bncr.ack`
|
|
33
|
+
- `bncr.ack` 保留兼容,当前主链路不强依赖。
|
|
27
34
|
|
|
28
35
|
> 结论:客户端最小实现只需两件事:
|
|
29
36
|
> 1) 发 `bncr.inbound`;2) 监听 `bncr.push`。
|
|
@@ -32,7 +39,7 @@ OpenClaw 的 Bncr WebSocket Bridge 频道插件(`channelId=bncr`)。
|
|
|
32
39
|
|
|
33
40
|
## 3. SessionKey 规则(严格)
|
|
34
41
|
|
|
35
|
-
|
|
42
|
+
标准格式(canonical):
|
|
36
43
|
|
|
37
44
|
```text
|
|
38
45
|
agent:main:bncr:direct:<hexScope>
|
|
@@ -40,28 +47,34 @@ agent:main:bncr:direct:<hexScope>
|
|
|
40
47
|
|
|
41
48
|
其中:
|
|
42
49
|
|
|
43
|
-
- `<hexScope>` = `platform:groupId:userId` 的 UTF-8
|
|
44
|
-
-
|
|
45
|
-
-
|
|
50
|
+
- `<hexScope>` = `platform:groupId:userId` 的 UTF-8 十六进制。
|
|
51
|
+
- 推荐使用小写 hex(插件兼容大小写输入)。
|
|
52
|
+
- 兼容输入会在内部归一到 `agent:main:bncr:direct:<hexScope>`。
|
|
46
53
|
|
|
47
54
|
示例:
|
|
48
55
|
|
|
49
56
|
```text
|
|
50
|
-
scope
|
|
51
|
-
hexScope
|
|
52
|
-
sessionKey= agent:main:bncr:direct:71713a303a383838383838
|
|
57
|
+
scope = qq:0:888888
|
|
58
|
+
hexScope = 71713a303a383838383838
|
|
59
|
+
sessionKey = agent:main:bncr:direct:71713a303a383838383838
|
|
53
60
|
```
|
|
54
61
|
|
|
55
62
|
---
|
|
56
63
|
|
|
57
64
|
## 4. Gateway Methods
|
|
58
65
|
|
|
59
|
-
|
|
66
|
+
插件注册方法:
|
|
60
67
|
|
|
61
68
|
- `bncr.connect`
|
|
62
69
|
- `bncr.inbound`
|
|
63
70
|
- `bncr.activity`
|
|
64
71
|
- `bncr.ack`
|
|
72
|
+
- `bncr.diagnostics`
|
|
73
|
+
- `bncr.file.init`
|
|
74
|
+
- `bncr.file.chunk`
|
|
75
|
+
- `bncr.file.complete`
|
|
76
|
+
- `bncr.file.abort`
|
|
77
|
+
- `bncr.file.ack`
|
|
65
78
|
|
|
66
79
|
---
|
|
67
80
|
|
|
@@ -100,6 +113,17 @@ sessionKey= agent:main:bncr:direct:71713a303a383838383838
|
|
|
100
113
|
"activeConnections": 1,
|
|
101
114
|
"pending": 0,
|
|
102
115
|
"deadLetter": 0,
|
|
116
|
+
"diagnostics": {
|
|
117
|
+
"health": {
|
|
118
|
+
"connected": true,
|
|
119
|
+
"pending": 0,
|
|
120
|
+
"deadLetter": 0,
|
|
121
|
+
"activeConnections": 1
|
|
122
|
+
},
|
|
123
|
+
"regression": {
|
|
124
|
+
"ok": true
|
|
125
|
+
}
|
|
126
|
+
},
|
|
103
127
|
"now": 1772476800000
|
|
104
128
|
}
|
|
105
129
|
}
|
|
@@ -211,61 +235,101 @@ sessionKey= agent:main:bncr:direct:71713a303a383838383838
|
|
|
211
235
|
- `platform`:必填
|
|
212
236
|
- `groupId`:可选,默认 `"0"`(私聊)
|
|
213
237
|
- `userId`:建议填写(私聊/群聊都建议带上)
|
|
214
|
-
- `sessionKey`:可选,建议传严格 sessionKey
|
|
238
|
+
- `sessionKey`:可选,建议传严格 sessionKey
|
|
215
239
|
- `msgId`:建议传(便于短窗口去重)
|
|
216
240
|
- `type`:`text/image/video/file/...`
|
|
217
241
|
- `msg`:文本
|
|
218
242
|
- `base64`:媒体 base64
|
|
243
|
+
- `path`:可选,文件直传完成后的落盘路径(与 `base64` 二选一)
|
|
219
244
|
- `mimeType` / `fileName`:媒体元数据(可选)
|
|
220
245
|
|
|
221
246
|
校验失败常见错误:
|
|
222
247
|
|
|
223
248
|
- `platform/groupId/userId required`
|
|
224
249
|
|
|
225
|
-
#### 6.1.1
|
|
250
|
+
#### 6.1.1 任务分流前缀(可选)
|
|
251
|
+
|
|
252
|
+
`msg` 支持前缀:
|
|
226
253
|
|
|
227
|
-
|
|
254
|
+
- `#task:foo`
|
|
255
|
+
- `/task:foo`
|
|
256
|
+
- `/task foo 正文...`
|
|
228
257
|
|
|
229
|
-
|
|
230
|
-
- 文本消息使用 `msg`,与当前插件读取一致。
|
|
231
|
-
- 媒体字段使用 `base64`(可带 `mimeType/fileName`),与当前插件读取一致。
|
|
232
|
-
- 默认账号建议使用 `Primary`,并与网关账户 ID 保持大小写一致。
|
|
258
|
+
命中后会把会话键附加为 `:task:<taskKey>` 用于子任务分流,ACK 中会返回 `taskKey`。
|
|
233
259
|
|
|
234
260
|
### 6.2 OpenClaw -> Bncr(`bncr.push`)
|
|
235
261
|
|
|
236
262
|
关键字段:
|
|
237
263
|
|
|
264
|
+
- `type`(固定 `message.outbound`)
|
|
238
265
|
- `messageId`
|
|
239
266
|
- `idempotencyKey`(当前等于 `messageId`)
|
|
240
267
|
- `sessionKey`
|
|
241
268
|
- `message.platform/groupId/userId`
|
|
242
|
-
- `message.type/msg/path/base64/fileName`
|
|
269
|
+
- `message.type/msg/path/base64/fileName/mimeType`
|
|
270
|
+
- `message.transferMode`(媒体场景可出现:`base64`/`chunk`)
|
|
243
271
|
- `ts`
|
|
244
272
|
|
|
245
273
|
说明:
|
|
246
274
|
|
|
247
275
|
- 主类型固定为 `type="message.outbound"`。
|
|
248
|
-
-
|
|
249
|
-
- 不附带 webchat 的 `stream/state/data` 语义字段。
|
|
276
|
+
- 推荐客户端仅消费 `message.outbound` 主链路。
|
|
250
277
|
|
|
251
278
|
---
|
|
252
279
|
|
|
253
280
|
## 7. `message.send(channel=bncr)` 目标解析规则(重要)
|
|
254
281
|
|
|
255
|
-
|
|
282
|
+
发送前支持并兼容以下 6 种目标输入:
|
|
283
|
+
|
|
284
|
+
1. `agent:main:bncr:direct:<hex>`
|
|
285
|
+
2. `agent:main:bncr:group:<hex>`
|
|
286
|
+
3. `bncr:<hex>`
|
|
287
|
+
4. `bncr:g-<hex>`
|
|
288
|
+
5. `bncr:<platform>:<groupId>:<userId>`
|
|
289
|
+
6. `bncr:g-<platform>:<groupId>:<userId>`
|
|
290
|
+
|
|
291
|
+
推荐写法:
|
|
292
|
+
|
|
293
|
+
- `to=bncr:<platform>:<groupId>:<userId>`
|
|
294
|
+
|
|
295
|
+
内部会做**反查校验**:
|
|
296
|
+
|
|
297
|
+
- 必须在已知会话路由中反查到真实 session 才发送。
|
|
298
|
+
- 查不到会报:`target not found in known sessions`。
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
## 8. 文件互传(V1)
|
|
303
|
+
|
|
304
|
+
### 8.1 OpenClaw -> Bncr(下行媒体)
|
|
305
|
+
|
|
306
|
+
当前默认 **强制分块**(chunk)传输:
|
|
307
|
+
|
|
308
|
+
- `bncr.file.init`
|
|
309
|
+
- `bncr.file.chunk`
|
|
310
|
+
- `bncr.file.complete`
|
|
311
|
+
- Bncr 客户端通过 `bncr.file.ack` 回 ACK
|
|
312
|
+
|
|
313
|
+
特性:
|
|
256
314
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
315
|
+
- 分块大小默认 256KB
|
|
316
|
+
- chunk ACK 超时/失败会重试
|
|
317
|
+
- 完成后 `message.outbound.message.path` 回填客户端可用路径
|
|
260
318
|
|
|
261
|
-
|
|
319
|
+
### 8.2 Bncr -> OpenClaw(上行文件)
|
|
262
320
|
|
|
263
|
-
|
|
264
|
-
|
|
321
|
+
Bncr 客户端可通过:
|
|
322
|
+
|
|
323
|
+
- `bncr.file.init`
|
|
324
|
+
- `bncr.file.chunk`
|
|
325
|
+
- `bncr.file.complete`
|
|
326
|
+
- `bncr.file.abort`
|
|
327
|
+
|
|
328
|
+
完成上传后,OpenClaw 会落盘并在后续 `bncr.inbound` 中通过 `path` 传递。
|
|
265
329
|
|
|
266
330
|
---
|
|
267
331
|
|
|
268
|
-
##
|
|
332
|
+
## 9. 可靠性
|
|
269
333
|
|
|
270
334
|
- 离线入队 + 重连自动冲队列。
|
|
271
335
|
- 指数退避:`1s,2s,4s,8s...`
|
|
@@ -274,53 +338,28 @@ sessionKey= agent:main:bncr:direct:71713a303a383838383838
|
|
|
274
338
|
|
|
275
339
|
---
|
|
276
340
|
|
|
277
|
-
##
|
|
341
|
+
## 10. 状态判定与诊断
|
|
278
342
|
|
|
279
343
|
- 实际链路在线:`linked`
|
|
280
344
|
- 已配置但离线:`configured`
|
|
281
|
-
-
|
|
345
|
+
- 账户卡片离线展示口径会显示 `Status`
|
|
282
346
|
|
|
283
347
|
常用状态字段:
|
|
284
348
|
|
|
285
349
|
- `pending`
|
|
286
350
|
- `deadLetter`
|
|
287
351
|
- `lastSessionKey`
|
|
288
|
-
- `lastSessionScope`(`
|
|
352
|
+
- `lastSessionScope`(`bncr:platform:group:user`)
|
|
289
353
|
- `lastSessionAt`
|
|
290
354
|
- `lastActivityAt`
|
|
291
355
|
- `lastInboundAt`
|
|
292
356
|
- `lastOutboundAt`
|
|
357
|
+
- `diagnostics`
|
|
293
358
|
|
|
294
|
-
|
|
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
|
-
}
|
|
317
|
-
```
|
|
318
|
-
|
|
319
|
-
`reason` 为可选自定义字段,插件会忽略业务外字段。
|
|
320
|
-
|
|
321
|
-
### `bncr.ack`
|
|
359
|
+
`diagnostics` 中包含:
|
|
322
360
|
|
|
323
|
-
|
|
361
|
+
- `health`:连接数、pending、dead-letter、事件计数、uptime
|
|
362
|
+
- `regression`:已知路由数、无效 sessionKey 残留、账号残留等
|
|
324
363
|
|
|
325
364
|
---
|
|
326
365
|
|
|
@@ -330,7 +369,7 @@ sessionKey= agent:main:bncr:direct:71713a303a383838383838
|
|
|
330
369
|
|
|
331
370
|
1. 先确认 `bncr.connect` 成功。
|
|
332
371
|
2. 客户端确认监听的是 `bncr.push`。
|
|
333
|
-
3. `sessionKey`
|
|
372
|
+
3. `sessionKey` 是否符合规范。
|
|
334
373
|
4. 若用 `message.send`,目标是否能反查到已知会话。
|
|
335
374
|
|
|
336
375
|
### Q2:为什么不需要 `bncr.pull`?
|
|
@@ -341,10 +380,15 @@ sessionKey= agent:main:bncr:direct:71713a303a383838383838
|
|
|
341
380
|
|
|
342
381
|
- 入站带稳定 `msgId`。
|
|
343
382
|
- 出站按 `idempotencyKey` 幂等处理。
|
|
344
|
-
-
|
|
383
|
+
- 客户端侧建议仅消费 `message.outbound`,并按需过滤 `NO_REPLY/HEARTBEAT_OK`。
|
|
384
|
+
|
|
385
|
+
### Q4:如何看桥接健康状态?
|
|
386
|
+
|
|
387
|
+
- 可直接调用 `bncr.diagnostics`。
|
|
388
|
+
- 或看 `bncr.connect`/状态卡片中的 `diagnostics` 字段。
|
|
345
389
|
|
|
346
390
|
---
|
|
347
391
|
|
|
348
392
|
## 12. 版本提示
|
|
349
393
|
|
|
350
|
-
历史版本接入过的话,请以当前文档(push-only +
|
|
394
|
+
历史版本接入过的话,请以当前文档(push-only + 6 格式目标兼容 + 文件互传 V1 + 诊断字段)为准。
|
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
|
|