@xmoxmo/bncr 0.6.0 → 0.6.2
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 +8 -0
- package/dist/index.js +2 -0
- package/index.ts +1 -0
- package/package.json +4 -1
- package/scripts/check-pack.mjs +41 -1
- package/scripts/selfcheck.mjs +4 -1
- package/src/bootstrap/register-runtime-gateway.ts +1 -0
- package/src/bootstrap/register-runtime.ts +1 -0
- package/src/channel.ts +66 -5
- package/src/core/types.ts +41 -0
- package/src/messaging/inbound/context-facts.ts +88 -58
- package/src/messaging/inbound/{group-history.ts → conversation-history.ts} +92 -25
- package/src/messaging/inbound/dispatch.ts +90 -47
- package/src/messaging/inbound/native-command.ts +1 -1
- package/src/messaging/inbound/outbound-replay-cache.ts +312 -0
- package/src/messaging/inbound/scene-admin.ts +24 -9
- package/src/messaging/inbound/turn-context.ts +105 -33
- package/src/plugin/ack-outbox-runtime-group.ts +2 -0
- package/src/plugin/bridge-call.ts +168 -0
- package/src/plugin/bridge-outbox-facade.ts +88 -1
- package/src/plugin/channel-components.ts +10 -5
- package/src/plugin/channel-plugin-bridge-group.ts +43 -1
- package/src/plugin/channel-plugin-surface-group.ts +82 -7
- package/src/plugin/channel-runtime-builders-delivery.ts +4 -2
- package/src/plugin/channel-runtime-types.ts +34 -8
- package/src/plugin/channel-send.ts +12 -19
- package/src/plugin/client-rpc-runtime.ts +129 -0
- package/src/plugin/gateway-methods.ts +1 -0
- package/src/plugin/inbound-acceptance.ts +9 -24
- package/src/plugin/inbound-handlers.ts +8 -4
- package/src/plugin/inbound-surface-handlers-group.ts +7 -2
- package/src/plugin/outbox-ack-outcome.ts +2 -0
- package/src/plugin/scene-registry.ts +4 -4
- package/src/plugin/state-store.ts +153 -29
- package/src/plugin/state-transient-runtime-group.ts +10 -3
package/README.md
CHANGED
|
@@ -81,6 +81,13 @@ openclaw devices approve --latest
|
|
|
81
81
|
- 状态诊断
|
|
82
82
|
- 文件互传
|
|
83
83
|
|
|
84
|
+
### 0.6.1 新增说明
|
|
85
|
+
|
|
86
|
+
- `bncr.outbound.recent`:本地 bridge 方法,可直接查询最近的出站记录;该记录来自出站重放缓存,不额外维护一份独立最近出站存储。
|
|
87
|
+
- 出站重放缓存:最近出站消息会在下轮入站上下文回灌时带给 agent,用于让 agent 知道自己刚发过什么;查询和回灌共享同一份 `outboundReplayCache`。
|
|
88
|
+
- bridge 方法调用:`message` 工具支持传入 `bridgeMethod`,可调用插件本地方法(如 `bncr.status.*`、`bncr.outbound.recent`)或转发到 OpenClawClient RPC。
|
|
89
|
+
- unsend / delete:`message` 工具支持撤回/删除动作,按发送缓存映射回真实平台消息,不需要业务侧单独拼平台 message id。
|
|
90
|
+
|
|
84
91
|
补充口径:
|
|
85
92
|
|
|
86
93
|
- 入站会话按正式 scene / route 语义接入 OpenClaw,区分私聊与群聊会话。
|
|
@@ -285,6 +292,7 @@ npm pack
|
|
|
285
292
|
- `npm run typecheck`:执行 `tsconfig.typecheck.json`,确保类型边界与 OpenClaw surface 对齐
|
|
286
293
|
- `npm run selfcheck`:检查插件骨架是否完整,并验证关键 OpenClaw SDK subpath 可解析
|
|
287
294
|
- `npm run check-pack`:执行 `npm pack --dry-run --json`,确认发布包包含关键入口与 OpenClaw adapter 文件
|
|
295
|
+
- `tests/integrity/source-manifest.test.mjs`:确保 `selfcheck` / `check-pack` 的源文件清单与当前 `src/**/*.ts` 一致,新增源文件不会漏进发布清单
|
|
288
296
|
- `npm run format:check`:执行 Biome `format` 只读检查(不带 `--write`),防止格式漂移混进发布门禁
|
|
289
297
|
- `npm pack`:确认当前版本可正常打包
|
|
290
298
|
- `npm run check-register-drift -- --duration-sec 300 --interval-sec 15`:静置采样 `bncr.diagnostics`,观察 `registerCount / apiGeneration / postWarmupRegisterCount` 是否在 warmup 后继续增长
|
package/dist/index.js
CHANGED
|
@@ -626,6 +626,7 @@ function createBncrRegisterRuntime() {
|
|
|
626
626
|
"bncr.diagnostics": (bridge, opts) => bridge.handleDiagnostics(opts),
|
|
627
627
|
"bncr.deadLetter.inspect": (bridge, opts) => bridge.handleDeadLetterInspect(opts),
|
|
628
628
|
"bncr.deadLetter.prune": (bridge, opts) => bridge.handleDeadLetterPrune(opts),
|
|
629
|
+
"bncr.rpc.response": (bridge, opts) => bridge.handleRpcResponse(opts),
|
|
629
630
|
"bncr.file.init": (bridge, opts) => bridge.handleFileInit(opts),
|
|
630
631
|
"bncr.file.chunk": (bridge, opts) => bridge.handleFileChunk(opts),
|
|
631
632
|
"bncr.file.complete": (bridge, opts) => bridge.handleFileComplete(opts),
|
|
@@ -936,6 +937,7 @@ var plugin = {
|
|
|
936
937
|
ensureGatewayMethodRegistered(api, "bncr.diagnostics", debugLog);
|
|
937
938
|
ensureGatewayMethodRegistered(api, "bncr.deadLetter.inspect", debugLog);
|
|
938
939
|
ensureGatewayMethodRegistered(api, "bncr.deadLetter.prune", debugLog);
|
|
940
|
+
ensureGatewayMethodRegistered(api, "bncr.rpc.response", debugLog);
|
|
939
941
|
ensureGatewayMethodRegistered(api, "bncr.file.init", debugLog);
|
|
940
942
|
ensureGatewayMethodRegistered(api, "bncr.file.chunk", debugLog);
|
|
941
943
|
ensureGatewayMethodRegistered(api, "bncr.file.complete", debugLog);
|
package/index.ts
CHANGED
|
@@ -208,6 +208,7 @@ const plugin = {
|
|
|
208
208
|
ensureGatewayMethodRegistered(api, 'bncr.diagnostics', debugLog);
|
|
209
209
|
ensureGatewayMethodRegistered(api, 'bncr.deadLetter.inspect', debugLog);
|
|
210
210
|
ensureGatewayMethodRegistered(api, 'bncr.deadLetter.prune', debugLog);
|
|
211
|
+
ensureGatewayMethodRegistered(api, 'bncr.rpc.response', debugLog);
|
|
211
212
|
ensureGatewayMethodRegistered(api, 'bncr.file.init', debugLog);
|
|
212
213
|
ensureGatewayMethodRegistered(api, 'bncr.file.chunk', debugLog);
|
|
213
214
|
ensureGatewayMethodRegistered(api, 'bncr.file.complete', debugLog);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xmoxmo/bncr",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -62,5 +62,8 @@
|
|
|
62
62
|
"runtimeExtensions": [
|
|
63
63
|
"./dist/index.js"
|
|
64
64
|
]
|
|
65
|
+
},
|
|
66
|
+
"dependencies": {
|
|
67
|
+
"typebox": "^1.3.10"
|
|
65
68
|
}
|
|
66
69
|
}
|
package/scripts/check-pack.mjs
CHANGED
|
@@ -48,7 +48,6 @@ const requiredSourceFiles = [
|
|
|
48
48
|
'src/core/outbox-summary.ts',
|
|
49
49
|
'src/core/outbox-text-push-failure.ts',
|
|
50
50
|
'src/core/outbox-text-push-guards.ts',
|
|
51
|
-
'src/core/outbox-text-push-prep.ts',
|
|
52
51
|
'src/core/outbox-text-push-success.ts',
|
|
53
52
|
'src/core/permissions.ts',
|
|
54
53
|
'src/core/persisted-outbox-entry.ts',
|
|
@@ -68,6 +67,7 @@ const requiredSourceFiles = [
|
|
|
68
67
|
'src/messaging/inbound/media-url-download.ts',
|
|
69
68
|
'src/messaging/inbound/native-command.ts',
|
|
70
69
|
'src/messaging/inbound/native-reply-delivery.ts',
|
|
70
|
+
'src/messaging/inbound/outbound-replay-cache.ts',
|
|
71
71
|
'src/messaging/inbound/parse.ts',
|
|
72
72
|
'src/messaging/inbound/remote-media.ts',
|
|
73
73
|
'src/messaging/inbound/reply-config.ts',
|
|
@@ -109,6 +109,8 @@ const requiredSourceFiles = [
|
|
|
109
109
|
'src/plugin/channel-runtime-types.ts',
|
|
110
110
|
'src/plugin/channel-send.ts',
|
|
111
111
|
'src/plugin/channel-utils.ts',
|
|
112
|
+
'src/plugin/bridge-call.ts',
|
|
113
|
+
'src/plugin/client-rpc-runtime.ts',
|
|
112
114
|
'src/plugin/config.ts',
|
|
113
115
|
'src/plugin/connection-handlers.ts',
|
|
114
116
|
'src/plugin/connection-state.ts',
|
|
@@ -168,6 +170,44 @@ const requiredSourceFiles = [
|
|
|
168
170
|
'src/runtime/register-trace-runtime.ts',
|
|
169
171
|
'src/runtime/status-snapshots.ts',
|
|
170
172
|
'src/runtime/status-worker.ts',
|
|
173
|
+
'src/bootstrap/register-runtime-gateway.ts',
|
|
174
|
+
'src/bootstrap/register-runtime-singleton.ts',
|
|
175
|
+
'src/core/value-sanitize.ts',
|
|
176
|
+
'src/messaging/inbound/contracts.ts',
|
|
177
|
+
'src/messaging/inbound/conversation-history.ts',
|
|
178
|
+
'src/messaging/inbound/native-command-runtime.ts',
|
|
179
|
+
'src/messaging/inbound/reply-dispatch-serial.ts',
|
|
180
|
+
'src/messaging/inbound/scene-admin.ts',
|
|
181
|
+
'src/messaging/inbound/session-meta-task.ts',
|
|
182
|
+
'src/messaging/outbound/marker-parser.ts',
|
|
183
|
+
'src/messaging/outbound/normalize-outbound-send.ts',
|
|
184
|
+
'src/messaging/outbound/reply-enqueue-media.ts',
|
|
185
|
+
'src/openclaw/channel-runtime-contracts.ts',
|
|
186
|
+
'src/plugin/bridge-ack-facade.ts',
|
|
187
|
+
'src/plugin/bridge-connection-facade.ts',
|
|
188
|
+
'src/plugin/bridge-diagnostics-facade.ts',
|
|
189
|
+
'src/plugin/bridge-drain-facade.ts',
|
|
190
|
+
'src/plugin/bridge-extended-diagnostics-facade.ts',
|
|
191
|
+
'src/plugin/bridge-lifecycle.ts',
|
|
192
|
+
'src/plugin/bridge-media-facade.ts',
|
|
193
|
+
'src/plugin/bridge-outbox-facade.ts',
|
|
194
|
+
'src/plugin/bridge-runtime-helpers.ts',
|
|
195
|
+
'src/plugin/bridge-runtime-snapshots.ts',
|
|
196
|
+
'src/plugin/bridge-runtime-surface-facade.ts',
|
|
197
|
+
'src/plugin/bridge-status-facade.ts',
|
|
198
|
+
'src/plugin/bridge-status-worker-facade.ts',
|
|
199
|
+
'src/plugin/bridge-support-runtime.ts',
|
|
200
|
+
'src/plugin/channel-runtime-builders-delivery.ts',
|
|
201
|
+
'src/plugin/channel-runtime-builders-status.ts',
|
|
202
|
+
'src/plugin/connection-handlers-helpers.ts',
|
|
203
|
+
'src/plugin/connection-state-helpers.ts',
|
|
204
|
+
'src/plugin/error-message.ts',
|
|
205
|
+
'src/plugin/file-transfer-orchestrator-chunk.ts',
|
|
206
|
+
'src/plugin/outbox-unified-push-flow.ts',
|
|
207
|
+
'src/plugin/runtime-diagnostics-assembler.ts',
|
|
208
|
+
'src/plugin/runtime-diagnostics-helpers.ts',
|
|
209
|
+
'src/plugin/runtime-diagnostics-payload-builders.ts',
|
|
210
|
+
'src/plugin/scene-registry.ts',
|
|
171
211
|
];
|
|
172
212
|
|
|
173
213
|
const requiredPackFiles = [
|
package/scripts/selfcheck.mjs
CHANGED
|
@@ -63,12 +63,13 @@ const requiredSourceFiles = [
|
|
|
63
63
|
'src/messaging/inbound/dispatch-prep.ts',
|
|
64
64
|
'src/messaging/inbound/dispatch.ts',
|
|
65
65
|
'src/messaging/inbound/gate.ts',
|
|
66
|
-
'src/messaging/inbound/
|
|
66
|
+
'src/messaging/inbound/conversation-history.ts',
|
|
67
67
|
'src/messaging/inbound/last-route.ts',
|
|
68
68
|
'src/messaging/inbound/media-url-download.ts',
|
|
69
69
|
'src/messaging/inbound/native-command-runtime.ts',
|
|
70
70
|
'src/messaging/inbound/native-command.ts',
|
|
71
71
|
'src/messaging/inbound/native-reply-delivery.ts',
|
|
72
|
+
'src/messaging/inbound/outbound-replay-cache.ts',
|
|
72
73
|
'src/messaging/inbound/parse.ts',
|
|
73
74
|
'src/messaging/inbound/remote-media.ts',
|
|
74
75
|
'src/messaging/inbound/reply-config.ts',
|
|
@@ -106,6 +107,7 @@ const requiredSourceFiles = [
|
|
|
106
107
|
'src/openclaw/session-route-runtime.ts',
|
|
107
108
|
'src/plugin/ack-outbox-runtime-group.ts',
|
|
108
109
|
'src/plugin/bridge-ack-facade.ts',
|
|
110
|
+
'src/plugin/bridge-call.ts',
|
|
109
111
|
'src/plugin/bridge-connection-facade.ts',
|
|
110
112
|
'src/plugin/bridge-diagnostics-facade.ts',
|
|
111
113
|
'src/plugin/bridge-drain-facade.ts',
|
|
@@ -133,6 +135,7 @@ const requiredSourceFiles = [
|
|
|
133
135
|
'src/plugin/channel-runtime-types.ts',
|
|
134
136
|
'src/plugin/channel-send.ts',
|
|
135
137
|
'src/plugin/channel-utils.ts',
|
|
138
|
+
'src/plugin/client-rpc-runtime.ts',
|
|
136
139
|
'src/plugin/config.ts',
|
|
137
140
|
'src/plugin/connection-handlers-helpers.ts',
|
|
138
141
|
'src/plugin/connection-handlers.ts',
|
|
@@ -97,6 +97,7 @@ export function createBncrRegisterRuntime() {
|
|
|
97
97
|
'bncr.diagnostics': (bridge, opts) => bridge.handleDiagnostics(opts),
|
|
98
98
|
'bncr.deadLetter.inspect': (bridge, opts) => bridge.handleDeadLetterInspect(opts),
|
|
99
99
|
'bncr.deadLetter.prune': (bridge, opts) => bridge.handleDeadLetterPrune(opts),
|
|
100
|
+
'bncr.rpc.response': (bridge, opts) => bridge.handleRpcResponse(opts),
|
|
100
101
|
'bncr.file.init': (bridge, opts) => bridge.handleFileInit(opts),
|
|
101
102
|
'bncr.file.chunk': (bridge, opts) => bridge.handleFileChunk(opts),
|
|
102
103
|
'bncr.file.complete': (bridge, opts) => bridge.handleFileComplete(opts),
|
package/src/channel.ts
CHANGED
|
@@ -4,7 +4,13 @@ import type {
|
|
|
4
4
|
OpenClawPluginApi,
|
|
5
5
|
OpenClawPluginServiceContext,
|
|
6
6
|
} from 'openclaw/plugin-sdk/core';
|
|
7
|
-
import {
|
|
7
|
+
import { DEFAULT_GROUP_HISTORY_LIMIT as DEFAULT_HISTORY_LIMIT } from 'openclaw/plugin-sdk/reply-history';
|
|
8
|
+
import {
|
|
9
|
+
BNCR_DEFAULT_ACCOUNT_ID,
|
|
10
|
+
CHANNEL_ID,
|
|
11
|
+
normalizeAccountId,
|
|
12
|
+
resolveAccount,
|
|
13
|
+
} from './core/accounts.ts';
|
|
8
14
|
import {
|
|
9
15
|
countInvalidOutboxSessionKeys as countInvalidOutboxSessionKeysFromRuntime,
|
|
10
16
|
countLegacyAccountResidue as countLegacyAccountResidueFromRuntime,
|
|
@@ -38,7 +44,8 @@ import type {
|
|
|
38
44
|
FileSendTransferState,
|
|
39
45
|
OutboxEntry,
|
|
40
46
|
} from './core/types.ts';
|
|
41
|
-
import type {
|
|
47
|
+
import type { BncrConversationHistoryMap } from './messaging/inbound/conversation-history.ts';
|
|
48
|
+
import type { BncrOutboundReplayCache } from './messaging/inbound/outbound-replay-cache.ts';
|
|
42
49
|
import type { parseBncrInboundParams } from './messaging/inbound/parse.ts';
|
|
43
50
|
import { buildEnqueueFromReplyDebugInfo } from './messaging/outbound/diagnostics.ts';
|
|
44
51
|
import { buildBncrMediaOutboundFrame } from './messaging/outbound/media.ts';
|
|
@@ -160,6 +167,7 @@ import {
|
|
|
160
167
|
now,
|
|
161
168
|
resolveOutboundFileName,
|
|
162
169
|
} from './plugin/channel-utils.ts';
|
|
170
|
+
import { createBncrClientRpcRuntime } from './plugin/client-rpc-runtime.ts';
|
|
163
171
|
import { BNCR_CONFIG_SURFACE } from './plugin/config.ts';
|
|
164
172
|
import { createBncrConnectionStateRuntimeGroup } from './plugin/connection-state-runtime-group.ts';
|
|
165
173
|
import type { FileAckPayloadState } from './plugin/file-ack-runtime.ts';
|
|
@@ -286,7 +294,8 @@ class BncrBridgeRuntime {
|
|
|
286
294
|
getSceneRegistry(): Map<string, BncrSceneRecord> {
|
|
287
295
|
return this.sceneRegistry;
|
|
288
296
|
}
|
|
289
|
-
private
|
|
297
|
+
private conversationHistories: BncrConversationHistoryMap = new Map();
|
|
298
|
+
private outboundReplayCache: BncrOutboundReplayCache = new Map();
|
|
290
299
|
private routeAliases = new Map<
|
|
291
300
|
string,
|
|
292
301
|
{ accountId: string; route: BncrRoute; updatedAt: number }
|
|
@@ -373,6 +382,14 @@ class BncrBridgeRuntime {
|
|
|
373
382
|
>();
|
|
374
383
|
private earlyFileAcks = new Map<string, FileAckPayloadState>();
|
|
375
384
|
|
|
385
|
+
private readonly clientRpcRuntime = createBncrClientRpcRuntime({
|
|
386
|
+
resolvePushConnIds: (accountId) => this.resolvePushConnIds(accountId),
|
|
387
|
+
broadcastToConnIds: (event, payload, connIds) =>
|
|
388
|
+
this.gatewayContext?.broadcastToConnIds(event, payload, connIds),
|
|
389
|
+
now,
|
|
390
|
+
logInfo: (scope, message, options) => this.logInfo(scope, message, options),
|
|
391
|
+
});
|
|
392
|
+
|
|
376
393
|
private readonly bridgeSupportRuntime = createBridgeSupportRuntime({
|
|
377
394
|
isStopped: () => this.stopped,
|
|
378
395
|
hasSaveTimer: () => Boolean(this.saveTimer),
|
|
@@ -851,6 +868,7 @@ class BncrBridgeRuntime {
|
|
|
851
868
|
}
|
|
852
869
|
|
|
853
870
|
private cleanupRuntimeWaitersAndTimers(reason: string) {
|
|
871
|
+
this.clientRpcRuntime.shutdown();
|
|
854
872
|
cleanupBncrBridgeRuntime(
|
|
855
873
|
{
|
|
856
874
|
bridgeId: this.bridgeId,
|
|
@@ -1759,6 +1777,7 @@ class BncrBridgeRuntime {
|
|
|
1759
1777
|
setOutboxEntry: (messageId, entry) => this.outbox.set(messageId, entry),
|
|
1760
1778
|
resolveMessageAck: (messageId, result) => this.resolveMessageAck(messageId, result),
|
|
1761
1779
|
moveToDeadLetter: (entry, reason) => this.moveToDeadLetter(entry, reason),
|
|
1780
|
+
markRecentOutboundAcked: (entry) => this.markRecentOutboundAcked(entry),
|
|
1762
1781
|
recordAckTimeoutTelemetry: (accountId) => this.recordAckTimeoutTelemetry(accountId),
|
|
1763
1782
|
degradeOutboundCapability: (args) => this.degradeOutboundCapability(args),
|
|
1764
1783
|
flushPushQueueBestEffort: (args) => this.flushPushQueueBestEffort(args),
|
|
@@ -1883,7 +1902,8 @@ class BncrBridgeRuntime {
|
|
|
1883
1902
|
maxSessionRouteEntries: MAX_SESSION_ROUTE_ENTRIES,
|
|
1884
1903
|
maxAccountActivityEntries: MAX_ACCOUNT_ACTIVITY_ENTRIES,
|
|
1885
1904
|
sceneRegistry: this.sceneRegistry,
|
|
1886
|
-
|
|
1905
|
+
conversationHistories: this.conversationHistories,
|
|
1906
|
+
outboundReplayCache: this.outboundReplayCache,
|
|
1887
1907
|
outbox: this.outbox,
|
|
1888
1908
|
getDeadLetter: () => this.deadLetter,
|
|
1889
1909
|
setDeadLetter: (entries) => {
|
|
@@ -2148,6 +2168,27 @@ class BncrBridgeRuntime {
|
|
|
2148
2168
|
lastPrePushGuardSkipReasonByAccount: this.lastPrePushGuardSkipReasonByAccount,
|
|
2149
2169
|
deadLetterSinceStartByAccount: this.deadLetterSinceStartByAccount,
|
|
2150
2170
|
lastOutboundByAccount: this.lastOutboundByAccount,
|
|
2171
|
+
outboundReplayCache: this.outboundReplayCache,
|
|
2172
|
+
conversationHistories: this.conversationHistories,
|
|
2173
|
+
resolveOutboundHistoryLimit: (entry) => {
|
|
2174
|
+
const platform = entry.route?.platform || '';
|
|
2175
|
+
const groupId = entry.route?.groupId || '0';
|
|
2176
|
+
const userId = entry.route?.userId || '0';
|
|
2177
|
+
const sceneKey = groupId !== '0' ? `${platform}:${groupId}` : `${platform}:${userId}`;
|
|
2178
|
+
const sceneLimit = this.sceneRegistry.get(sceneKey)?.historyLimit;
|
|
2179
|
+
return typeof sceneLimit === 'number' && Number.isFinite(sceneLimit) && sceneLimit >= 0
|
|
2180
|
+
? Math.floor(sceneLimit)
|
|
2181
|
+
: DEFAULT_HISTORY_LIMIT;
|
|
2182
|
+
},
|
|
2183
|
+
resolveOutboundSender: (entry) => {
|
|
2184
|
+
try {
|
|
2185
|
+
const account = resolveAccount(getOpenClawRuntimeConfig(this.api), entry.accountId);
|
|
2186
|
+
return { sender: account.name, senderId: entry.accountId };
|
|
2187
|
+
} catch {
|
|
2188
|
+
return { sender: 'OpenClaw', senderId: entry.accountId };
|
|
2189
|
+
}
|
|
2190
|
+
},
|
|
2191
|
+
isOutboundAckRequired: (accountId) => this.isOutboundAckRequired(accountId),
|
|
2151
2192
|
scheduleSave: () => this.scheduleSave(),
|
|
2152
2193
|
flushPushQueueBestEffort: (args) => this.flushPushQueueBestEffort(args),
|
|
2153
2194
|
logInfo: (scope, message, options) => this.logInfo(scope, message, options),
|
|
@@ -2722,6 +2763,18 @@ class BncrBridgeRuntime {
|
|
|
2722
2763
|
return this.bridgeMediaFacade.enqueueFromReply(params);
|
|
2723
2764
|
}
|
|
2724
2765
|
|
|
2766
|
+
listRecentOutbound(sessionKey: string) {
|
|
2767
|
+
return this.bridgeOutboxFacade.listRecentOutbound(sessionKey);
|
|
2768
|
+
}
|
|
2769
|
+
|
|
2770
|
+
listRecentOutboundByAccount(accountId: string) {
|
|
2771
|
+
return this.bridgeOutboxFacade.listRecentOutboundByAccount(accountId);
|
|
2772
|
+
}
|
|
2773
|
+
|
|
2774
|
+
private markRecentOutboundAcked(entry: OutboxEntry) {
|
|
2775
|
+
this.bridgeOutboxFacade.markRecentOutboundAcked(entry);
|
|
2776
|
+
}
|
|
2777
|
+
|
|
2725
2778
|
private logEnqueueFromReply(args: {
|
|
2726
2779
|
accountId: string;
|
|
2727
2780
|
sessionKey: string;
|
|
@@ -2852,7 +2905,8 @@ class BncrBridgeRuntime {
|
|
|
2852
2905
|
defaultAdminAgentId: (args) => this.defaultAdminAgentId(args),
|
|
2853
2906
|
defaultPublicAgentId: () => this.defaultPublicAgentId(),
|
|
2854
2907
|
sceneRegistry: this.sceneRegistry,
|
|
2855
|
-
|
|
2908
|
+
conversationHistories: this.conversationHistories,
|
|
2909
|
+
outboundReplayCache: this.outboundReplayCache,
|
|
2856
2910
|
prepareInboundAcceptance: (args) => this.prepareInboundAcceptance(args),
|
|
2857
2911
|
logInboundSummary: (args) => this.logInboundSummary(args),
|
|
2858
2912
|
flushPushQueueBestEffort: (args) => this.flushPushQueueBestEffort(args),
|
|
@@ -2922,6 +2976,12 @@ class BncrBridgeRuntime {
|
|
|
2922
2976
|
handleDeadLetterPrune = async (ctx: GatewayRequestHandlerOptions) =>
|
|
2923
2977
|
this.diagnosticsHandlers.handleDeadLetterPrune(ctx);
|
|
2924
2978
|
|
|
2979
|
+
handleRpcResponse = async (ctx: GatewayRequestHandlerOptions) =>
|
|
2980
|
+
this.clientRpcRuntime.handleResponse(ctx);
|
|
2981
|
+
|
|
2982
|
+
callClientRpc = async (method: string, args: Record<string, unknown>, accountId: string) =>
|
|
2983
|
+
this.clientRpcRuntime.call(method, args, normalizeAccountId(accountId));
|
|
2984
|
+
|
|
2925
2985
|
handleFileInit = async (ctx: GatewayRequestHandlerOptions) =>
|
|
2926
2986
|
this.fileInboundHandlers.handleFileInit(ctx);
|
|
2927
2987
|
|
|
@@ -3024,6 +3084,7 @@ export function createBncrChannelPlugin(getBridge: () => BncrBridgeRuntime) {
|
|
|
3024
3084
|
getStatusBridge: bridgeGroup.getStatusBridge,
|
|
3025
3085
|
getToolActionBridge: bridgeGroup.getToolActionBridge,
|
|
3026
3086
|
getGatewayBridge: bridgeGroup.getGatewayBridge,
|
|
3087
|
+
getBridgeCallBridge: bridgeGroup.getBridgeCallBridge,
|
|
3027
3088
|
channelMeta: BNCR_CHANNEL_META,
|
|
3028
3089
|
channelCapabilities: BNCR_CHANNEL_CAPABILITIES,
|
|
3029
3090
|
gatewayMethods: BNCR_GATEWAY_METHODS,
|
package/src/core/types.ts
CHANGED
|
@@ -118,6 +118,47 @@ export type OutboxEntry = {
|
|
|
118
118
|
awaitingRetryPush?: boolean;
|
|
119
119
|
};
|
|
120
120
|
|
|
121
|
+
export type BncrRecentOutboundEntry = {
|
|
122
|
+
messageId: string;
|
|
123
|
+
accountId: string;
|
|
124
|
+
sessionKey: string;
|
|
125
|
+
route: BncrRoute;
|
|
126
|
+
type?: string;
|
|
127
|
+
kind?: string;
|
|
128
|
+
text: string;
|
|
129
|
+
mediaUrl?: string;
|
|
130
|
+
createdAt: number;
|
|
131
|
+
lastPushAt?: number;
|
|
132
|
+
lastError?: string;
|
|
133
|
+
ackedAt?: number;
|
|
134
|
+
status: 'queued' | 'pushed' | 'failed' | 'acked';
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
export type BncrOutboundReplayMediaEntry = {
|
|
138
|
+
path?: string;
|
|
139
|
+
contentType?: string;
|
|
140
|
+
kind?: 'image' | 'video' | 'audio' | 'document' | 'unknown';
|
|
141
|
+
messageId?: string;
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
export type BncrOutboundReplayStatus = 'pushed' | 'acked';
|
|
145
|
+
|
|
146
|
+
export type BncrOutboundReplayEntry = {
|
|
147
|
+
sender: string;
|
|
148
|
+
senderId?: string;
|
|
149
|
+
body: string;
|
|
150
|
+
timestamp?: number;
|
|
151
|
+
messageId?: string;
|
|
152
|
+
media?: BncrOutboundReplayMediaEntry[];
|
|
153
|
+
accountId?: string;
|
|
154
|
+
sessionKey?: string;
|
|
155
|
+
route?: BncrRoute;
|
|
156
|
+
type?: string;
|
|
157
|
+
mediaUrl?: string;
|
|
158
|
+
createdAt?: number;
|
|
159
|
+
status?: BncrOutboundReplayStatus;
|
|
160
|
+
};
|
|
161
|
+
|
|
121
162
|
export type BncrDiagnosticsSummary = {
|
|
122
163
|
health: {
|
|
123
164
|
connected: boolean;
|
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
|
|
3
|
+
type BncrConversationContextMedia = {
|
|
4
|
+
type?: string;
|
|
5
|
+
path?: string;
|
|
6
|
+
contentType?: string;
|
|
7
|
+
kind?: string;
|
|
8
|
+
messageId?: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
type BncrConversationContextEntry = {
|
|
12
|
+
messageId?: string;
|
|
13
|
+
timestamp?: number;
|
|
14
|
+
role?: 'user' | 'assistant' | 'system';
|
|
15
|
+
sender?: string;
|
|
16
|
+
senderId?: string;
|
|
17
|
+
content?: string;
|
|
18
|
+
media?: BncrConversationContextMedia[];
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
type BncrParticipantRecord = Record<
|
|
22
|
+
string,
|
|
23
|
+
{
|
|
24
|
+
name: string;
|
|
25
|
+
username?: string;
|
|
26
|
+
isBot?: boolean;
|
|
27
|
+
isAdmin?: boolean;
|
|
28
|
+
isOwner?: boolean;
|
|
29
|
+
isAuthorizedSender?: boolean;
|
|
30
|
+
role?: 'owner' | 'admin' | 'user';
|
|
31
|
+
displayName?: string;
|
|
32
|
+
}
|
|
33
|
+
>;
|
|
34
|
+
|
|
3
35
|
export type BncrStructuredContextFactsInput = {
|
|
4
36
|
channelId: string;
|
|
5
37
|
accountId: string;
|
|
@@ -57,18 +89,10 @@ export type BncrStructuredContextFactsInput = {
|
|
|
57
89
|
kind?: string;
|
|
58
90
|
messageId?: string;
|
|
59
91
|
}>;
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
body?: string;
|
|
65
|
-
media?: Array<{
|
|
66
|
-
path?: string;
|
|
67
|
-
contentType?: string;
|
|
68
|
-
kind?: string;
|
|
69
|
-
messageId?: string;
|
|
70
|
-
}>;
|
|
71
|
-
}>;
|
|
92
|
+
conversationContext?: BncrConversationContextEntry[];
|
|
93
|
+
participants?: BncrParticipantRecord | null;
|
|
94
|
+
isGroupChat?: boolean;
|
|
95
|
+
groupSubject?: string;
|
|
72
96
|
};
|
|
73
97
|
|
|
74
98
|
function toBncrPromptMediaPath(id: string): string | undefined {
|
|
@@ -166,18 +190,24 @@ export function buildBncrStructuredContextFacts(input: BncrStructuredContextFact
|
|
|
166
190
|
kind: item.kind,
|
|
167
191
|
messageId: item.messageId,
|
|
168
192
|
})),
|
|
169
|
-
|
|
193
|
+
conversationContext: (input.conversationContext || []).map((entry) => ({
|
|
170
194
|
messageId: entry.messageId,
|
|
195
|
+
timestamp: entry.timestamp,
|
|
196
|
+
role: entry.role,
|
|
171
197
|
sender: entry.sender,
|
|
172
198
|
senderId: entry.senderId,
|
|
173
|
-
|
|
199
|
+
content: entry.content,
|
|
174
200
|
media: (entry.media || []).map((item) => ({
|
|
201
|
+
type: item.type || item.kind || 'document',
|
|
175
202
|
path: item.path,
|
|
176
203
|
contentType: item.contentType,
|
|
177
|
-
kind: item.kind,
|
|
178
204
|
messageId: item.messageId,
|
|
179
205
|
})),
|
|
180
206
|
})),
|
|
207
|
+
participants: input.participants ?? null,
|
|
208
|
+
isGroupChat: input.isGroupChat,
|
|
209
|
+
groupSubject: input.groupSubject,
|
|
210
|
+
accountId: input.accountId,
|
|
181
211
|
};
|
|
182
212
|
}
|
|
183
213
|
|
|
@@ -210,18 +240,11 @@ export function buildBncrPromptVisibleContextFacts(
|
|
|
210
240
|
kind?: string;
|
|
211
241
|
messageId?: string;
|
|
212
242
|
}>;
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
media?: Array<{
|
|
219
|
-
path?: string;
|
|
220
|
-
contentType?: string;
|
|
221
|
-
kind?: string;
|
|
222
|
-
messageId?: string;
|
|
223
|
-
}>;
|
|
224
|
-
}>;
|
|
243
|
+
conversation_context?: Array<Record<string, unknown>>;
|
|
244
|
+
participants?: BncrParticipantRecord;
|
|
245
|
+
is_group_chat?: boolean;
|
|
246
|
+
group_subject?: string;
|
|
247
|
+
account_id?: string;
|
|
225
248
|
} = {};
|
|
226
249
|
|
|
227
250
|
if (facts.platform) {
|
|
@@ -272,27 +295,39 @@ export function buildBncrPromptVisibleContextFacts(
|
|
|
272
295
|
return Object.values(payload).some((field) => field !== undefined) ? [payload] : [];
|
|
273
296
|
});
|
|
274
297
|
}
|
|
275
|
-
if (facts.
|
|
276
|
-
result.
|
|
277
|
-
const
|
|
298
|
+
if (facts.conversationContext?.length) {
|
|
299
|
+
result.conversation_context = facts.conversationContext.flatMap((entry) => {
|
|
300
|
+
const items: Array<Record<string, unknown>> = [];
|
|
301
|
+
if (entry.content) {
|
|
302
|
+
items.push({
|
|
303
|
+
messageId: entry.messageId,
|
|
304
|
+
timestamp: entry.timestamp,
|
|
305
|
+
role: entry.role,
|
|
306
|
+
sender: entry.sender,
|
|
307
|
+
senderId: entry.senderId,
|
|
308
|
+
content: entry.content,
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
for (const item of entry.media || []) {
|
|
278
312
|
const promptMediaPath = resolveBncrPromptMediaPath(item.path);
|
|
279
313
|
const payload = {
|
|
314
|
+
messageId: item.messageId ?? entry.messageId,
|
|
315
|
+
timestamp: entry.timestamp,
|
|
316
|
+
role: entry.role,
|
|
317
|
+
sender: entry.sender,
|
|
318
|
+
senderId: entry.senderId,
|
|
319
|
+
media_type: item.type || 'document',
|
|
280
320
|
...(promptMediaPath ? { path: promptMediaPath } : {}),
|
|
281
|
-
contentType: item.contentType,
|
|
282
|
-
kind: item.kind,
|
|
283
|
-
messageId: item.messageId,
|
|
321
|
+
...(item.contentType ? { contentType: item.contentType } : {}),
|
|
284
322
|
};
|
|
285
|
-
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
messageId: entry.messageId,
|
|
289
|
-
sender: entry.sender,
|
|
290
|
-
senderId: entry.senderId,
|
|
291
|
-
body: entry.body,
|
|
292
|
-
...(media.length > 0 ? { media } : {}),
|
|
293
|
-
};
|
|
294
|
-
return Object.values(payload).some((field) => field !== undefined) ? [payload] : [];
|
|
323
|
+
if (Object.values(payload).some((field) => field !== undefined)) items.push(payload);
|
|
324
|
+
}
|
|
325
|
+
return items;
|
|
295
326
|
});
|
|
327
|
+
if (facts.participants) result.participants = facts.participants;
|
|
328
|
+
if (facts.isGroupChat !== undefined) result.is_group_chat = facts.isGroupChat;
|
|
329
|
+
if (facts.groupSubject) result.group_subject = facts.groupSubject;
|
|
330
|
+
if (facts.accountId) result.account_id = facts.accountId;
|
|
296
331
|
}
|
|
297
332
|
|
|
298
333
|
return result;
|
|
@@ -358,25 +393,17 @@ export type BncrStructuredContextFactsFromInboundPartsInput = {
|
|
|
358
393
|
bridgeSenderName?: string;
|
|
359
394
|
senderIsOwner?: boolean;
|
|
360
395
|
senderIsAuthorized?: boolean;
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
body?: string;
|
|
366
|
-
media?: Array<{
|
|
367
|
-
path?: string;
|
|
368
|
-
contentType?: string;
|
|
369
|
-
kind?: string;
|
|
370
|
-
messageId?: string;
|
|
371
|
-
}>;
|
|
372
|
-
}>;
|
|
396
|
+
conversationHistoryContext?: BncrConversationContextEntry[];
|
|
397
|
+
participants?: BncrParticipantRecord | null;
|
|
398
|
+
isGroupChat?: boolean;
|
|
399
|
+
groupSubject?: string;
|
|
373
400
|
};
|
|
374
401
|
export function buildBncrStructuredContextFactsFromInboundParts(
|
|
375
402
|
input: BncrStructuredContextFactsFromInboundPartsInput,
|
|
376
403
|
) {
|
|
377
404
|
const mediaItems = Array.isArray(input.prepared.mediaItems) ? input.prepared.mediaItems : [];
|
|
378
|
-
const
|
|
379
|
-
? input.
|
|
405
|
+
const conversationHistoryContext = Array.isArray(input.conversationHistoryContext)
|
|
406
|
+
? input.conversationHistoryContext
|
|
380
407
|
: [];
|
|
381
408
|
return buildBncrStructuredContextFacts({
|
|
382
409
|
channelId: input.channelId,
|
|
@@ -435,6 +462,9 @@ export function buildBncrStructuredContextFactsFromInboundParts(
|
|
|
435
462
|
kind: item.kind || inferBncrStructuredMediaKind(item.contentType),
|
|
436
463
|
messageId: input.parsed.msgId,
|
|
437
464
|
})),
|
|
438
|
-
|
|
465
|
+
conversationContext: conversationHistoryContext,
|
|
466
|
+
participants: input.participants ?? null,
|
|
467
|
+
isGroupChat: input.isGroupChat,
|
|
468
|
+
groupSubject: input.groupSubject,
|
|
439
469
|
});
|
|
440
470
|
}
|