@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.
Files changed (4) hide show
  1. package/README.md +106 -62
  2. package/index.ts +24 -0
  3. package/package.json +1 -1
  4. 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` 兼容保留,当前不是必需链路(fire-and-forget)。
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 hex(小写)。
44
- - 仅允许 `0-9a-f` 且长度为偶数。
45
- - 旧格式(如 `...:<hexScope>:0`)不再作为标准形态。
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 = qq:0:888888
51
- hexScope = 71713a303a383838383838
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(见第 3 节)
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 openclawclient.js(发送端)对齐说明
250
+ #### 6.1.1 任务分流前缀(可选)
251
+
252
+ `msg` 支持前缀:
226
253
 
227
- 基于你当前附件版本(`openclawclient` 注释版本 `0.0.2`)核对结果:
254
+ - `#task:foo`
255
+ - `/task:foo`
256
+ - `/task foo 正文...`
228
257
 
229
- - `inboundSend()` 使用 `sessionKey`,与当前插件入站字段一致。
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
- - 仅输出嵌套结构 `message.{...}`,不再输出平铺兼容字段。
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
- 1. 严格 `sessionKey`
258
- 2. `platform:groupId:userId`
259
- 3. `Bncr-platform:groupId:userId`
315
+ - 分块大小默认 256KB
316
+ - chunk ACK 超时/失败会重试
317
+ - 完成后 `message.outbound.message.path` 回填客户端可用路径
260
318
 
261
- 但发送前会做**反查校验**:
319
+ ### 8.2 Bncr -> OpenClaw(上行文件)
262
320
 
263
- - 必须在已知会话路由里反查到真实 `sessionKey` 才会发送。
264
- - 禁止拼凑 key 直接发;查不到会报:`target not found in known sessions`。
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
- ## 8. 重试与可靠性
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
- ## 9. 状态判定与观测
341
+ ## 10. 状态判定与诊断
278
342
 
279
343
  - 实际链路在线:`linked`
280
344
  - 已配置但离线:`configured`
281
- - 账户卡片中离线模式会显示 `Status`(展示口径)
345
+ - 账户卡片离线展示口径会显示 `Status`
282
346
 
283
347
  常用状态字段:
284
348
 
285
349
  - `pending`
286
350
  - `deadLetter`
287
351
  - `lastSessionKey`
288
- - `lastSessionScope`(`Bncr-platform:group:user`)
352
+ - `lastSessionScope`(`bncr:platform:group:user`)
289
353
  - `lastSessionAt`
290
354
  - `lastActivityAt`
291
355
  - `lastInboundAt`
292
356
  - `lastOutboundAt`
357
+ - `diagnostics`
293
358
 
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
- }
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
- - 客户端侧建议只消费 `message.outbound` 主链路。
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 + strict sessionKey + 目标反查)为准。
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
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xmoxmo/bncr",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "license": "MIT",