@xmoxmo/bncr 0.3.5 → 0.3.7
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 +5 -0
- package/dist/index.js +28 -5
- package/index.ts +55 -721
- package/package.json +8 -4
- package/scripts/check-pack.mjs +93 -18
- package/scripts/check-register-drift.mjs +35 -13
- package/scripts/selfcheck.mjs +80 -11
- package/src/bootstrap/channel-plugin-runtime.ts +81 -0
- package/src/bootstrap/cli.ts +97 -0
- package/src/bootstrap/register-runtime-gateway.ts +129 -0
- package/src/bootstrap/register-runtime-helpers.ts +140 -0
- package/src/bootstrap/register-runtime-singleton.ts +137 -0
- package/src/bootstrap/register-runtime.ts +201 -0
- package/src/bootstrap/runtime-discovery.ts +187 -0
- package/src/bootstrap/runtime-loader.ts +54 -0
- package/src/channel.ts +1590 -4967
- package/src/core/accounts.ts +23 -4
- package/src/core/dead-letter-diagnostics.ts +37 -5
- package/src/core/diagnostics.ts +31 -15
- package/src/core/downlink-health.ts +3 -11
- package/src/core/extended-diagnostics.ts +78 -36
- package/src/core/file-transfer-payloads.ts +1 -1
- package/src/core/logging.ts +1 -0
- package/src/core/outbox-enqueue.ts +13 -2
- package/src/core/outbox-entry-builders.ts +2 -0
- package/src/core/outbox-summary.ts +75 -3
- package/src/core/permissions.ts +15 -2
- package/src/core/persisted-outbox-entry.ts +21 -6
- package/src/core/policy.ts +45 -4
- package/src/core/probe.ts +3 -15
- package/src/core/register-trace.ts +3 -3
- package/src/core/status.ts +43 -4
- package/src/core/targets.ts +216 -205
- package/src/core/types.ts +221 -0
- package/src/core/value-sanitize.ts +29 -0
- package/src/messaging/inbound/commands.ts +147 -172
- package/src/messaging/inbound/context-facts.ts +4 -2
- package/src/messaging/inbound/contracts.ts +70 -0
- package/src/messaging/inbound/dispatch-prep.ts +303 -0
- package/src/messaging/inbound/dispatch.ts +49 -462
- package/src/messaging/inbound/gate.ts +18 -5
- package/src/messaging/inbound/last-route.ts +10 -4
- package/src/messaging/inbound/media-url-download.ts +109 -0
- package/src/messaging/inbound/native-command-runtime.ts +225 -0
- package/src/messaging/inbound/parse.ts +2 -1
- package/src/messaging/inbound/remote-media.ts +49 -0
- package/src/messaging/inbound/reply-config.ts +16 -4
- package/src/messaging/inbound/reply-dispatch.ts +162 -0
- package/src/messaging/inbound/runtime-compat.ts +31 -10
- package/src/messaging/inbound/session-label.ts +15 -7
- package/src/messaging/inbound/turn-context.ts +131 -0
- package/src/messaging/outbound/actions.ts +24 -10
- package/src/messaging/outbound/diagnostics-debug-builders.ts +365 -0
- package/src/messaging/outbound/diagnostics.ts +31 -355
- package/src/messaging/outbound/durable-message-adapter.ts +20 -16
- package/src/messaging/outbound/durable-queue-adapter.ts +20 -7
- package/src/messaging/outbound/media.ts +24 -13
- package/src/messaging/outbound/reply-enqueue-media.ts +181 -0
- package/src/messaging/outbound/reply-enqueue.ts +57 -134
- package/src/messaging/outbound/send-params.ts +3 -0
- package/src/messaging/outbound/send.ts +19 -10
- package/src/messaging/outbound/session-route.ts +18 -3
- package/src/openclaw/channel-runtime-contracts.ts +76 -0
- package/src/openclaw/config-runtime.ts +13 -7
- package/src/openclaw/inbound-session-runtime.ts +7 -3
- package/src/openclaw/ingress-runtime.ts +17 -27
- package/src/openclaw/reply-runtime.ts +54 -59
- package/src/openclaw/routing-runtime.ts +35 -18
- package/src/openclaw/runtime-surface.ts +156 -12
- package/src/openclaw/sdk-helpers.ts +8 -1
- package/src/openclaw/session-route-runtime.ts +12 -12
- package/src/plugin/ack-outbox-runtime-group.ts +264 -0
- package/src/plugin/bridge-ack-facade.ts +137 -0
- package/src/plugin/bridge-connection-facade.ts +111 -0
- package/src/plugin/bridge-diagnostics-facade.ts +23 -0
- package/src/plugin/bridge-drain-facade.ts +98 -0
- package/src/plugin/bridge-extended-diagnostics-facade.ts +149 -0
- package/src/plugin/bridge-file-transfer-push-facade.ts +140 -0
- package/src/plugin/bridge-lifecycle.ts +156 -0
- package/src/plugin/bridge-media-facade.ts +241 -0
- package/src/plugin/bridge-outbox-facade.ts +182 -0
- package/src/plugin/bridge-runtime-helpers.ts +266 -0
- package/src/plugin/bridge-runtime-snapshots.ts +104 -0
- package/src/plugin/bridge-runtime-surface-facade.ts +8 -0
- package/src/plugin/bridge-status-facade.ts +76 -0
- package/src/plugin/bridge-status-worker-facade.ts +72 -0
- package/src/plugin/bridge-support-runtime.ts +137 -0
- package/src/plugin/bridge-surface-handlers-group.ts +242 -0
- package/src/plugin/bridge-surface-helpers.ts +28 -0
- package/src/plugin/capabilities.ts +1 -3
- package/src/plugin/channel-components.ts +289 -0
- package/src/plugin/channel-inbound-helpers.ts +149 -0
- package/src/plugin/channel-plugin-bridge-group.ts +129 -0
- package/src/plugin/channel-plugin-surface-group.ts +202 -0
- package/src/plugin/channel-runtime-builders-delivery.ts +513 -0
- package/src/plugin/channel-runtime-builders-status.ts +331 -0
- package/src/plugin/channel-runtime-builders.ts +25 -0
- package/src/plugin/channel-runtime-constants.ts +40 -0
- package/src/plugin/channel-runtime-types.ts +146 -0
- package/src/plugin/channel-send-runtime-group.ts +37 -0
- package/src/plugin/channel-send.ts +226 -0
- package/src/plugin/channel-utils.ts +102 -0
- package/src/plugin/config.ts +24 -3
- package/src/plugin/connection-handlers-helpers.ts +254 -0
- package/src/plugin/connection-handlers.ts +440 -0
- package/src/plugin/connection-state-helpers.ts +159 -0
- package/src/plugin/connection-state-runtime-group.ts +51 -0
- package/src/plugin/connection-state.ts +527 -0
- package/src/plugin/diagnostics-handlers.ts +211 -0
- package/src/plugin/error-message.ts +15 -0
- package/src/plugin/file-ack-runtime.ts +284 -0
- package/src/plugin/file-inbound-abort.ts +112 -0
- package/src/plugin/file-inbound-chunk.ts +146 -0
- package/src/plugin/file-inbound-complete.ts +153 -0
- package/src/plugin/file-inbound-handlers.ts +19 -0
- package/src/plugin/file-inbound-init.ts +122 -0
- package/src/plugin/file-inbound-runtime.ts +51 -0
- package/src/plugin/file-inbound-state.ts +62 -0
- package/src/plugin/file-transfer-logs.ts +227 -0
- package/src/plugin/file-transfer-orchestrator-chunk.ts +135 -0
- package/src/plugin/file-transfer-orchestrator.ts +304 -0
- package/src/plugin/file-transfer-runtime-group.ts +102 -0
- package/src/plugin/file-transfer-send.ts +89 -0
- package/src/plugin/file-transfer-setup.ts +206 -0
- package/src/plugin/gateway-event-context.ts +41 -0
- package/src/plugin/gateway-runtime.ts +14 -4
- package/src/plugin/inbound-acceptance.ts +107 -0
- package/src/plugin/inbound-handlers.ts +248 -0
- package/src/plugin/inbound-surface-handlers-group.ts +152 -0
- package/src/plugin/media-dedupe-runtime.ts +90 -0
- package/src/plugin/media-orchestrators-runtime-group.ts +316 -0
- package/src/plugin/message-ack-runtime.ts +284 -0
- package/src/plugin/message-send.ts +16 -6
- package/src/plugin/messaging.ts +98 -36
- package/src/plugin/outbound.ts +50 -8
- package/src/plugin/outbox-ack-logs.ts +136 -0
- package/src/plugin/outbox-ack-outcome.ts +128 -0
- package/src/plugin/outbox-drain-ack.ts +145 -0
- package/src/plugin/outbox-drain-failure.ts +84 -0
- package/src/plugin/outbox-drain-loop.ts +554 -0
- package/src/plugin/outbox-drain-post-push.ts +159 -0
- package/src/plugin/outbox-drain-runtime.ts +141 -0
- package/src/plugin/outbox-drain-schedule.ts +116 -0
- package/src/plugin/outbox-file-push-flow.ts +69 -0
- package/src/plugin/outbox-push-route-runtime-group.ts +81 -0
- package/src/plugin/outbox-push.ts +267 -0
- package/src/plugin/outbox-route.ts +181 -0
- package/src/plugin/outbox-text-push-flow.ts +90 -0
- package/src/plugin/runtime-diagnostics-assembler.ts +183 -0
- package/src/plugin/runtime-diagnostics-helpers.ts +302 -0
- package/src/plugin/runtime-diagnostics-payload-builders.ts +171 -0
- package/src/plugin/runtime-diagnostics-snapshot.ts +31 -0
- package/src/plugin/setup.ts +33 -6
- package/src/plugin/state-store.ts +249 -0
- package/src/plugin/state-transient-runtime-group.ts +105 -0
- package/src/plugin/status-runtime.ts +251 -0
- package/src/plugin/status.ts +33 -7
- package/src/plugin/target-runtime.ts +141 -0
- package/src/plugin/target-status-runtime-group.ts +130 -0
- package/src/plugin/transient-state-runtime.ts +82 -0
- package/src/runtime/outbound-ack-timeout.ts +5 -3
- package/src/runtime/outbound-flags.ts +24 -8
- package/src/runtime/status-snapshots.ts +36 -7
- package/src/runtime/status-worker.ts +34 -4
package/src/core/types.ts
CHANGED
|
@@ -10,6 +10,85 @@ export type BncrConnection = {
|
|
|
10
10
|
clientId?: string;
|
|
11
11
|
connectedAt: number;
|
|
12
12
|
lastSeenAt: number;
|
|
13
|
+
inboundOnly?: boolean;
|
|
14
|
+
outboundReady?: boolean;
|
|
15
|
+
preferredForOutbound?: boolean;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export type BncrGatewayCapabilityFlags = {
|
|
19
|
+
outboundReady: boolean;
|
|
20
|
+
preferredForOutbound: boolean;
|
|
21
|
+
inboundOnly: boolean;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export type FileRecvTransferStatus = 'init' | 'transferring' | 'completed' | 'aborted';
|
|
25
|
+
|
|
26
|
+
type FileRecvTransferBase = {
|
|
27
|
+
transferId: string;
|
|
28
|
+
accountId: string;
|
|
29
|
+
sessionKey: string;
|
|
30
|
+
route: BncrRoute;
|
|
31
|
+
fileName: string;
|
|
32
|
+
mimeType: string;
|
|
33
|
+
fileSize: number;
|
|
34
|
+
chunkSize: number;
|
|
35
|
+
totalChunks: number;
|
|
36
|
+
fileSha256: string;
|
|
37
|
+
startedAt: number;
|
|
38
|
+
bufferByChunk: Map<number, Buffer>;
|
|
39
|
+
receivedChunks: Set<number>;
|
|
40
|
+
ownerConnId?: string;
|
|
41
|
+
ownerClientId?: string;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export type FileRecvTransferInitState = FileRecvTransferBase & {
|
|
45
|
+
status: 'init';
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export type FileRecvTransferTransferringState = FileRecvTransferBase & {
|
|
49
|
+
status: 'transferring';
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export type FileRecvTransferCompletedState = FileRecvTransferBase & {
|
|
53
|
+
status: 'completed';
|
|
54
|
+
completedPath: string;
|
|
55
|
+
terminalAt: number;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export type FileRecvTransferAbortedState = FileRecvTransferBase & {
|
|
59
|
+
status: 'aborted';
|
|
60
|
+
terminalAt: number;
|
|
61
|
+
error: string;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export type FileRecvTransferState =
|
|
65
|
+
| FileRecvTransferInitState
|
|
66
|
+
| FileRecvTransferTransferringState
|
|
67
|
+
| FileRecvTransferCompletedState
|
|
68
|
+
| FileRecvTransferAbortedState;
|
|
69
|
+
|
|
70
|
+
export type FileSendTransferStatus = 'init' | 'transferring' | 'completed' | 'aborted';
|
|
71
|
+
|
|
72
|
+
export type FileSendTransferState = {
|
|
73
|
+
transferId: string;
|
|
74
|
+
accountId: string;
|
|
75
|
+
sessionKey: string;
|
|
76
|
+
route: BncrRoute;
|
|
77
|
+
fileName: string;
|
|
78
|
+
mimeType: string;
|
|
79
|
+
fileSize: number;
|
|
80
|
+
chunkSize: number;
|
|
81
|
+
totalChunks: number;
|
|
82
|
+
fileSha256: string;
|
|
83
|
+
startedAt: number;
|
|
84
|
+
status: FileSendTransferStatus;
|
|
85
|
+
ackedChunks: Set<number>;
|
|
86
|
+
failedChunks: Map<number, string>;
|
|
87
|
+
ownerConnId?: string;
|
|
88
|
+
ownerClientId?: string;
|
|
89
|
+
completedPath?: string;
|
|
90
|
+
terminalAt?: number;
|
|
91
|
+
error?: string;
|
|
13
92
|
};
|
|
14
93
|
|
|
15
94
|
export type PendingAdmission = {
|
|
@@ -78,3 +157,145 @@ export type BncrDiagnosticsSummary = {
|
|
|
78
157
|
ok: boolean;
|
|
79
158
|
};
|
|
80
159
|
};
|
|
160
|
+
|
|
161
|
+
export type BncrDeadLetterDiagnosticsSummary = {
|
|
162
|
+
total: number;
|
|
163
|
+
allAccountsTotal: number;
|
|
164
|
+
sinceStart: number;
|
|
165
|
+
cappedAt: number;
|
|
166
|
+
oldestAt: number | null;
|
|
167
|
+
newestAt: number | null;
|
|
168
|
+
topReasons: Array<{ reason: string; count: number }>;
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
export type BncrDeadLetterEntrySummary = {
|
|
172
|
+
messageId: string;
|
|
173
|
+
accountId: string;
|
|
174
|
+
sessionKey: string;
|
|
175
|
+
route: string;
|
|
176
|
+
kind: string;
|
|
177
|
+
createdAt: number | null;
|
|
178
|
+
retryCount: number;
|
|
179
|
+
lastError: string | null;
|
|
180
|
+
textPreview: string;
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
export type BncrDownlinkHealthSummary = {
|
|
184
|
+
pendingOutbox: number;
|
|
185
|
+
oldestPendingCreatedAt: number | null;
|
|
186
|
+
oldestPendingAgeMs: number;
|
|
187
|
+
lastAckOkAt: number | null;
|
|
188
|
+
lastAckTimeoutAt: number | null;
|
|
189
|
+
recentAckTimeoutCount: number;
|
|
190
|
+
activeConnectionCount: number;
|
|
191
|
+
recentInboundReachable: boolean;
|
|
192
|
+
onlineByConn: boolean;
|
|
193
|
+
ackStalled: boolean;
|
|
194
|
+
recommendReconnect: boolean;
|
|
195
|
+
recommendReason: string;
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
export type BncrAckObservability = {
|
|
199
|
+
lastAckOkAt: number | null;
|
|
200
|
+
lastAckTimeoutAt: number | null;
|
|
201
|
+
recentAckTimeoutCount: number;
|
|
202
|
+
lateAckOkCount: number;
|
|
203
|
+
lastLateAckOkAt: number | null;
|
|
204
|
+
lastLateAckAgeMs: number | null;
|
|
205
|
+
lateAckObservationTtlMs: number;
|
|
206
|
+
lateAckObservationExpired: boolean;
|
|
207
|
+
adaptiveAckRecoveryOkCount: number;
|
|
208
|
+
adaptiveAckRecoveryOkThreshold: number;
|
|
209
|
+
adaptiveAckRecovered: boolean;
|
|
210
|
+
lastAckQueueLatencyMs: number | null;
|
|
211
|
+
lastAckPushLatencyMs: number | null;
|
|
212
|
+
lastLateAckQueueLatencyMs: number | null;
|
|
213
|
+
lastLateAckPushLatencyMs: number | null;
|
|
214
|
+
adaptiveAckTimeoutEnabled: boolean;
|
|
215
|
+
defaultAckTimeoutMs: number;
|
|
216
|
+
currentAckTimeoutMs: number;
|
|
217
|
+
recommendedAckTimeoutMs: number;
|
|
218
|
+
recommendedAckTimeoutReason: string;
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
export type BncrAckStrategy = {
|
|
222
|
+
mode: 'adaptive' | 'fixed';
|
|
223
|
+
currentMs: number;
|
|
224
|
+
defaultMs: number;
|
|
225
|
+
maxMs: number;
|
|
226
|
+
reason: string;
|
|
227
|
+
active: boolean;
|
|
228
|
+
lastLateAckAgeMs: number | null;
|
|
229
|
+
lateAckObservationTtlMs: number | null;
|
|
230
|
+
recovered: boolean;
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
export type BncrStaleCounterSummary = {
|
|
234
|
+
staleConnect: number;
|
|
235
|
+
staleInbound: number;
|
|
236
|
+
staleActivity: number;
|
|
237
|
+
staleAck: number;
|
|
238
|
+
staleFileInit: number;
|
|
239
|
+
staleFileChunk: number;
|
|
240
|
+
staleFileComplete: number;
|
|
241
|
+
staleFileAbort: number;
|
|
242
|
+
lastStaleAt: number | null;
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
export type BncrRuntimeLastSession = {
|
|
246
|
+
sessionKey: string;
|
|
247
|
+
scope: string;
|
|
248
|
+
updatedAt: number;
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
export type BncrOutboxQueueDiagnostics = {
|
|
252
|
+
pending: number;
|
|
253
|
+
pendingAllAccounts: number;
|
|
254
|
+
oldestPendingAt: number | null;
|
|
255
|
+
newestPendingAt: number | null;
|
|
256
|
+
lastAttemptAt: number | null;
|
|
257
|
+
lastPushAt: number | null;
|
|
258
|
+
lastPushError: string | null;
|
|
259
|
+
activeOutboundConnection: boolean;
|
|
260
|
+
activeOutboundConnectionCount: number;
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
export type BncrOutboxIncidentAckSummary = {
|
|
264
|
+
lastQueueLatencyMs: number | null;
|
|
265
|
+
lastPushLatencyMs: number | null;
|
|
266
|
+
lastLateQueueLatencyMs: number | null;
|
|
267
|
+
lastLatePushLatencyMs: number | null;
|
|
268
|
+
lastLateAckAgeMs: number | null;
|
|
269
|
+
adaptiveTimeoutMs: number | null;
|
|
270
|
+
adaptiveTimeoutReason: string | null;
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
export type BncrOutboxIncidentSummary = {
|
|
274
|
+
active: boolean;
|
|
275
|
+
type: string;
|
|
276
|
+
severity: 'ok' | 'warning' | 'critical';
|
|
277
|
+
recommendedAction: string;
|
|
278
|
+
pending: number;
|
|
279
|
+
oldestPendingAgeMs: number | null;
|
|
280
|
+
lastAttemptAgeMs: number | null;
|
|
281
|
+
lastPushAgeMs: number | null;
|
|
282
|
+
lastPushError: string | null;
|
|
283
|
+
hasGatewayContext: boolean;
|
|
284
|
+
activeOutboundConnection: boolean;
|
|
285
|
+
activeOutboundConnectionCount: number;
|
|
286
|
+
prePushGuardSkipCount: number;
|
|
287
|
+
lastPrePushGuardSkipAgeMs: number | null;
|
|
288
|
+
lastPrePushGuardSkipReason: string | null;
|
|
289
|
+
ack: BncrOutboxIncidentAckSummary;
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
export type BncrExtendedOutboundDiagnostics = BncrOutboxQueueDiagnostics & {
|
|
293
|
+
enqueueCount: number;
|
|
294
|
+
lastEnqueueAt: number | null;
|
|
295
|
+
prePushGuardSkipCount: number;
|
|
296
|
+
lastPrePushGuardSkipAt: number | null;
|
|
297
|
+
lastPrePushGuardSkipReason: string | null;
|
|
298
|
+
hasGatewayContext: boolean;
|
|
299
|
+
lastGatewayContextAt: number | null;
|
|
300
|
+
incident: BncrOutboxIncidentSummary;
|
|
301
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export function asSanitizedString(value: unknown, fallback = ''): string {
|
|
2
|
+
if (typeof value === 'string') return value;
|
|
3
|
+
if (value == null) return fallback;
|
|
4
|
+
return String(value);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function finiteNumberOr(value: unknown, fallback: number): number {
|
|
8
|
+
const n = Number(value);
|
|
9
|
+
return Number.isFinite(n) ? n : fallback;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function finiteNumberOrNull(value: unknown): number | null {
|
|
13
|
+
const n = Number(value);
|
|
14
|
+
return Number.isFinite(n) ? n : null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function nonNegativeFiniteNumberOr(value: unknown, fallback: number): number {
|
|
18
|
+
return Math.max(0, finiteNumberOr(value, fallback));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function clampFiniteNumber(
|
|
22
|
+
value: unknown,
|
|
23
|
+
fallback: number,
|
|
24
|
+
min: number,
|
|
25
|
+
max: number,
|
|
26
|
+
): number {
|
|
27
|
+
const finite = finiteNumberOr(value, fallback);
|
|
28
|
+
return Math.max(min, Math.min(finite, max));
|
|
29
|
+
}
|
|
@@ -1,21 +1,37 @@
|
|
|
1
1
|
import { emitBncrLogLine } from '../../core/logging.ts';
|
|
2
2
|
import { resolveBncrChannelPolicy } from '../../core/policy.ts';
|
|
3
|
-
import {
|
|
4
|
-
formatDisplayScope,
|
|
5
|
-
normalizeInboundSessionKey,
|
|
6
|
-
withTaskSessionKey,
|
|
7
|
-
} from '../../core/targets.ts';
|
|
3
|
+
import { formatDisplayScope } from '../../core/targets.ts';
|
|
8
4
|
import {
|
|
9
5
|
recordBncrInboundSession,
|
|
10
6
|
resolveBncrInboundSessionStorePath,
|
|
11
7
|
resolveBncrPinnedMainDmOwnerFromAllowlist,
|
|
12
8
|
} from '../../openclaw/inbound-session-runtime.ts';
|
|
13
9
|
import { dispatchOpenClawReplyWithBufferedBlockDispatcher } from '../../openclaw/reply-runtime.ts';
|
|
14
|
-
import {
|
|
15
|
-
|
|
10
|
+
import {
|
|
11
|
+
type OpenClawResolvedAgentRoute,
|
|
12
|
+
resolveOpenClawAgentRoute,
|
|
13
|
+
} from '../../openclaw/routing-runtime.ts';
|
|
14
|
+
import type {
|
|
15
|
+
BncrEnqueueFromReply,
|
|
16
|
+
BncrInboundApi,
|
|
17
|
+
BncrInboundConfig,
|
|
18
|
+
BncrInboundLogger,
|
|
19
|
+
BncrRememberSessionRoute,
|
|
20
|
+
} from './contracts.ts';
|
|
21
|
+
import type { ParsedInbound } from './dispatch-prep.ts';
|
|
16
22
|
import { buildBncrInboundRecordUpdateLastRoute } from './last-route.ts';
|
|
17
23
|
import { parseBncrNativeCommand, resolveBncrNativeVerboseCommand } from './native-command.ts';
|
|
18
|
-
import {
|
|
24
|
+
import {
|
|
25
|
+
buildBncrNativeCommandSessionState,
|
|
26
|
+
buildBncrNativeCommandSummary,
|
|
27
|
+
buildNativeCommandHandledResult,
|
|
28
|
+
buildNativeCommandRecordErrorLogger,
|
|
29
|
+
createNativeCommandReplyDeliverer,
|
|
30
|
+
createNativeCommandTurnContext,
|
|
31
|
+
logBncrNativeCommandEvent,
|
|
32
|
+
logBncrNativeCommandSummary,
|
|
33
|
+
resolveNativeCommandDebugEnabled,
|
|
34
|
+
} from './native-command-runtime.ts';
|
|
19
35
|
import { buildBncrReplyConfig } from './reply-config.ts';
|
|
20
36
|
import { resolveBncrChannelInboundRuntime } from './runtime-compat.ts';
|
|
21
37
|
import {
|
|
@@ -24,54 +40,63 @@ import {
|
|
|
24
40
|
wrapBncrInboundRecordSessionLabelCorrection,
|
|
25
41
|
} from './session-label.ts';
|
|
26
42
|
|
|
27
|
-
|
|
43
|
+
function assertResolvedAgentRoute(resolvedRoute: OpenClawResolvedAgentRoute): {
|
|
44
|
+
sessionKey: string;
|
|
45
|
+
agentId: string;
|
|
46
|
+
mainSessionKey?: string;
|
|
47
|
+
} {
|
|
48
|
+
const sessionKey =
|
|
49
|
+
typeof resolvedRoute.sessionKey === 'string' ? resolvedRoute.sessionKey.trim() : '';
|
|
50
|
+
const agentId = typeof resolvedRoute.agentId === 'string' ? resolvedRoute.agentId.trim() : '';
|
|
51
|
+
if (!sessionKey) throw new Error('OpenClaw resolveAgentRoute returned empty sessionKey');
|
|
52
|
+
if (!agentId) throw new Error('OpenClaw resolveAgentRoute returned empty agentId');
|
|
53
|
+
return {
|
|
54
|
+
sessionKey,
|
|
55
|
+
agentId,
|
|
56
|
+
...(typeof resolvedRoute.mainSessionKey === 'string' && resolvedRoute.mainSessionKey.trim()
|
|
57
|
+
? { mainSessionKey: resolvedRoute.mainSessionKey }
|
|
58
|
+
: {}),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
28
61
|
|
|
29
|
-
function
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
62
|
+
function buildBncrNativeCommandResolvedRoute(args: {
|
|
63
|
+
api: BncrInboundApi;
|
|
64
|
+
cfg: BncrInboundConfig;
|
|
65
|
+
channelId: string;
|
|
66
|
+
accountId: string;
|
|
67
|
+
peer: ParsedInbound['peer'];
|
|
68
|
+
}) {
|
|
69
|
+
return assertResolvedAgentRoute(
|
|
70
|
+
resolveOpenClawAgentRoute(args.api, {
|
|
71
|
+
cfg: args.cfg,
|
|
72
|
+
channel: args.channelId,
|
|
73
|
+
accountId: args.accountId,
|
|
74
|
+
peer: args.peer,
|
|
75
|
+
}),
|
|
76
|
+
);
|
|
36
77
|
}
|
|
37
78
|
|
|
38
79
|
export { parseBncrNativeCommand } from './native-command.ts';
|
|
39
80
|
|
|
40
81
|
export async function handleBncrNativeCommand(params: {
|
|
41
|
-
api:
|
|
82
|
+
api: BncrInboundApi;
|
|
42
83
|
channelId: string;
|
|
43
|
-
cfg:
|
|
84
|
+
cfg: BncrInboundConfig;
|
|
44
85
|
parsed: ParsedInbound;
|
|
45
86
|
canonicalAgentId: string;
|
|
46
|
-
rememberSessionRoute:
|
|
47
|
-
enqueueFromReply:
|
|
48
|
-
|
|
49
|
-
sessionKey: string;
|
|
50
|
-
route: any;
|
|
51
|
-
payload: { text?: string; mediaUrl?: string; mediaUrls?: string[] };
|
|
52
|
-
mediaLocalRoots?: readonly string[];
|
|
53
|
-
replyTargetPolicy?: OutboundReplyTargetPolicy;
|
|
54
|
-
}) => Promise<void>;
|
|
55
|
-
logger?: { warn?: (msg: string) => void; error?: (msg: string) => void };
|
|
87
|
+
rememberSessionRoute: BncrRememberSessionRoute;
|
|
88
|
+
enqueueFromReply: BncrEnqueueFromReply;
|
|
89
|
+
logger?: BncrInboundLogger;
|
|
56
90
|
}): Promise<
|
|
57
91
|
| { handled: false }
|
|
58
92
|
| { handled: true; command: string; sessionKey: string; fallbackToAgent?: boolean }
|
|
59
93
|
> {
|
|
60
94
|
const { api, channelId, cfg, parsed, canonicalAgentId, rememberSessionRoute, enqueueFromReply } =
|
|
61
95
|
params;
|
|
62
|
-
const {
|
|
63
|
-
accountId,
|
|
64
|
-
route,
|
|
65
|
-
peer,
|
|
66
|
-
sessionKeyfromroute,
|
|
67
|
-
providedOriginatingTo,
|
|
68
|
-
clientId,
|
|
69
|
-
extracted,
|
|
70
|
-
msgId,
|
|
71
|
-
} = parsed;
|
|
96
|
+
const { accountId, route, peer, clientId, extracted, msgId } = parsed;
|
|
72
97
|
const command = parseBncrNativeCommand(extracted.text);
|
|
73
98
|
if (!command) return { handled: false };
|
|
74
|
-
const nativeCommandDebugEnabled = cfg
|
|
99
|
+
const nativeCommandDebugEnabled = resolveNativeCommandDebugEnabled({ cfg, channelId });
|
|
75
100
|
|
|
76
101
|
logBncrNativeCommandEvent(
|
|
77
102
|
'detected',
|
|
@@ -84,24 +109,23 @@ export async function handleBncrNativeCommand(params: {
|
|
|
84
109
|
{ debugOnly: true, debugEnabled: nativeCommandDebugEnabled },
|
|
85
110
|
);
|
|
86
111
|
|
|
87
|
-
const resolvedRoute =
|
|
112
|
+
const resolvedRoute = buildBncrNativeCommandResolvedRoute({
|
|
113
|
+
api,
|
|
88
114
|
cfg,
|
|
89
|
-
|
|
115
|
+
channelId,
|
|
90
116
|
accountId,
|
|
91
117
|
peer,
|
|
92
118
|
});
|
|
93
119
|
|
|
94
|
-
const baseSessionKey =
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
120
|
+
const { baseSessionKey, taskSessionKey, sessionKey, displayTo, originatingTo } =
|
|
121
|
+
buildBncrNativeCommandSessionState({
|
|
122
|
+
parsed,
|
|
123
|
+
canonicalAgentId,
|
|
124
|
+
resolvedRoute,
|
|
125
|
+
});
|
|
99
126
|
rememberSessionRoute(baseSessionKey, accountId, route);
|
|
100
127
|
if (taskSessionKey && taskSessionKey !== baseSessionKey)
|
|
101
128
|
rememberSessionRoute(taskSessionKey, accountId, route);
|
|
102
|
-
|
|
103
|
-
const displayTo = formatDisplayScope(route);
|
|
104
|
-
const originatingTo = providedOriginatingTo || displayTo;
|
|
105
129
|
const body = command.body;
|
|
106
130
|
if (!clientId) {
|
|
107
131
|
emitBncrLogLine(
|
|
@@ -116,72 +140,22 @@ export async function handleBncrNativeCommand(params: {
|
|
|
116
140
|
agentId: resolvedRoute.agentId,
|
|
117
141
|
});
|
|
118
142
|
|
|
119
|
-
const ctxPayload =
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
accountId,
|
|
124
|
-
messageId: msgId,
|
|
125
|
-
timestamp: Date.now(),
|
|
126
|
-
from: senderIdForContext,
|
|
127
|
-
sender: {
|
|
128
|
-
id: senderIdForContext,
|
|
129
|
-
name: senderDisplayName,
|
|
130
|
-
username: senderDisplayName,
|
|
131
|
-
},
|
|
132
|
-
conversation: {
|
|
133
|
-
kind: peer.kind,
|
|
134
|
-
id: peer.id,
|
|
135
|
-
label: displayTo,
|
|
136
|
-
routePeer: {
|
|
137
|
-
kind: peer.kind,
|
|
138
|
-
id: peer.id,
|
|
139
|
-
},
|
|
140
|
-
},
|
|
141
|
-
route: {
|
|
142
|
-
agentId: resolvedRoute.agentId,
|
|
143
|
+
const ctxPayload = await Promise.resolve(
|
|
144
|
+
createNativeCommandTurnContext({
|
|
145
|
+
api,
|
|
146
|
+
channelId,
|
|
143
147
|
accountId,
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
to: displayTo,
|
|
148
|
+
msgId: msgId || undefined,
|
|
149
|
+
peer,
|
|
150
|
+
resolvedRoute,
|
|
151
|
+
sessionKey,
|
|
152
|
+
displayTo,
|
|
150
153
|
originatingTo,
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
message: {
|
|
154
|
-
inboundEventKind: 'user_request',
|
|
155
|
-
body,
|
|
156
|
-
rawBody: body,
|
|
157
|
-
bodyForAgent: body,
|
|
158
|
-
commandBody: body,
|
|
159
|
-
envelopeFrom: originatingTo,
|
|
160
|
-
senderLabel: senderDisplayName,
|
|
161
|
-
},
|
|
162
|
-
commandTurn: {
|
|
163
|
-
kind: 'native',
|
|
164
|
-
source: 'native',
|
|
165
|
-
authorized: true,
|
|
154
|
+
senderIdForContext,
|
|
155
|
+
senderDisplayName,
|
|
166
156
|
body,
|
|
167
|
-
},
|
|
168
|
-
|
|
169
|
-
mentions: {
|
|
170
|
-
canDetectMention: true,
|
|
171
|
-
wasMentioned: true,
|
|
172
|
-
effectiveWasMentioned: true,
|
|
173
|
-
},
|
|
174
|
-
commands: {
|
|
175
|
-
authorized: true,
|
|
176
|
-
allowTextCommands: true,
|
|
177
|
-
useAccessGroups: false,
|
|
178
|
-
authorizers: [],
|
|
179
|
-
},
|
|
180
|
-
},
|
|
181
|
-
extra: {
|
|
182
|
-
OriginatingChannel: channelId,
|
|
183
|
-
},
|
|
184
|
-
});
|
|
157
|
+
}),
|
|
158
|
+
);
|
|
185
159
|
|
|
186
160
|
const sessionIdentityPatch = buildBncrInboundSessionIdentityPatch({
|
|
187
161
|
channelId,
|
|
@@ -193,14 +167,28 @@ export async function handleBncrNativeCommand(params: {
|
|
|
193
167
|
|
|
194
168
|
const nativeVerbose = resolveBncrNativeVerboseCommand(command);
|
|
195
169
|
if (nativeVerbose) {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
170
|
+
logBncrNativeCommandSummary(
|
|
171
|
+
buildBncrNativeCommandSummary({
|
|
172
|
+
kind: 'verbose',
|
|
173
|
+
command: command.command,
|
|
174
|
+
accountId,
|
|
175
|
+
to: displayTo,
|
|
176
|
+
msgId: msgId || null,
|
|
177
|
+
result: 'handled',
|
|
178
|
+
}),
|
|
179
|
+
);
|
|
180
|
+
logBncrNativeCommandEvent(
|
|
181
|
+
'handled-verbose',
|
|
182
|
+
{
|
|
183
|
+
command: command.command,
|
|
184
|
+
accountId,
|
|
185
|
+
sessionKey,
|
|
186
|
+
to: displayTo,
|
|
187
|
+
msgId: msgId || null,
|
|
188
|
+
fallbackToAgent: false,
|
|
189
|
+
},
|
|
190
|
+
{ debugOnly: true, debugEnabled: nativeCommandDebugEnabled },
|
|
191
|
+
);
|
|
204
192
|
await recordAndPatchBncrInboundSessionEntry({
|
|
205
193
|
storePath,
|
|
206
194
|
sessionKey,
|
|
@@ -235,7 +223,7 @@ export async function handleBncrNativeCommand(params: {
|
|
|
235
223
|
const pinnedMainDmOwner =
|
|
236
224
|
peer.kind === 'direct'
|
|
237
225
|
? resolveBncrPinnedMainDmOwnerFromAllowlist({
|
|
238
|
-
dmScope: cfg?.session?.dmScope,
|
|
226
|
+
dmScope: cfg?.session?.dmScope as string | undefined,
|
|
239
227
|
allowFrom: channelPolicy.allowFrom,
|
|
240
228
|
normalizeEntry: (entry: string) => String(entry || '').trim(),
|
|
241
229
|
})
|
|
@@ -283,16 +271,15 @@ export async function handleBncrNativeCommand(params: {
|
|
|
283
271
|
storePath,
|
|
284
272
|
ctxPayload,
|
|
285
273
|
recordInboundSession: wrapBncrInboundRecordSessionLabelCorrection({
|
|
286
|
-
recordInboundSession: recordBncrInboundSession
|
|
274
|
+
recordInboundSession: recordBncrInboundSession as (
|
|
275
|
+
...args: unknown[]
|
|
276
|
+
) => Promise<unknown> | unknown,
|
|
287
277
|
expectedLabel: displayTo,
|
|
288
278
|
}),
|
|
289
279
|
record: {
|
|
290
280
|
updateLastRoute,
|
|
291
281
|
onRecordError: (err: unknown) => {
|
|
292
|
-
|
|
293
|
-
'warn',
|
|
294
|
-
`[bncr] inbound record native command session failed: ${String(err)}`,
|
|
295
|
-
);
|
|
282
|
+
buildNativeCommandRecordErrorLogger(err);
|
|
296
283
|
},
|
|
297
284
|
},
|
|
298
285
|
runDispatch: () =>
|
|
@@ -300,47 +287,21 @@ export async function handleBncrNativeCommand(params: {
|
|
|
300
287
|
ctx: ctxPayload,
|
|
301
288
|
cfg: effectiveReply.replyCfg,
|
|
302
289
|
dispatcherOptions: {
|
|
303
|
-
deliver:
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
290
|
+
deliver: createNativeCommandReplyDeliverer({
|
|
291
|
+
command: command.command,
|
|
292
|
+
accountId,
|
|
293
|
+
sessionKey,
|
|
294
|
+
to: displayTo,
|
|
295
|
+
msgId: msgId || undefined,
|
|
296
|
+
effectiveReply,
|
|
297
|
+
route,
|
|
298
|
+
enqueueFromReply,
|
|
299
|
+
nativeCommandDebugEnabled,
|
|
300
|
+
onResponded: () => responded,
|
|
301
|
+
markResponded: () => {
|
|
302
|
+
responded = true;
|
|
309
303
|
},
|
|
310
|
-
|
|
311
|
-
) => {
|
|
312
|
-
const kind = info?.kind;
|
|
313
|
-
const deliveryPayload = buildBncrNativeReplyDeliveryPayload({
|
|
314
|
-
payload,
|
|
315
|
-
kind,
|
|
316
|
-
effectiveReply,
|
|
317
|
-
msgId,
|
|
318
|
-
});
|
|
319
|
-
if (!deliveryPayload) return;
|
|
320
|
-
if (!responded) {
|
|
321
|
-
logBncrNativeCommandEvent(
|
|
322
|
-
'payload-produced',
|
|
323
|
-
{
|
|
324
|
-
command: command.command,
|
|
325
|
-
accountId,
|
|
326
|
-
sessionKey,
|
|
327
|
-
to: displayTo,
|
|
328
|
-
msgId: msgId || null,
|
|
329
|
-
kind: kind || null,
|
|
330
|
-
fallbackToAgent: false,
|
|
331
|
-
},
|
|
332
|
-
{ debugOnly: true, debugEnabled: nativeCommandDebugEnabled },
|
|
333
|
-
);
|
|
334
|
-
}
|
|
335
|
-
responded = true;
|
|
336
|
-
await enqueueFromReply({
|
|
337
|
-
accountId,
|
|
338
|
-
sessionKey,
|
|
339
|
-
route,
|
|
340
|
-
payload: deliveryPayload,
|
|
341
|
-
replyTargetPolicy: 'preserve',
|
|
342
|
-
});
|
|
343
|
-
},
|
|
304
|
+
}),
|
|
344
305
|
},
|
|
345
306
|
replyOptions: {
|
|
346
307
|
disableBlockStreaming: !effectiveReply.blockStreaming,
|
|
@@ -352,15 +313,26 @@ export async function handleBncrNativeCommand(params: {
|
|
|
352
313
|
});
|
|
353
314
|
|
|
354
315
|
if (!responded) {
|
|
355
|
-
|
|
316
|
+
logBncrNativeCommandSummary(
|
|
317
|
+
`fallback command=${command.command}|accountId=${accountId}|to=${displayTo}|msgId=${msgId || '-'}|reason=no-payload`,
|
|
318
|
+
);
|
|
319
|
+
logBncrNativeCommandEvent(
|
|
320
|
+
'no-payload-fallback-to-agent',
|
|
321
|
+
{
|
|
322
|
+
command: command.command,
|
|
323
|
+
accountId,
|
|
324
|
+
sessionKey,
|
|
325
|
+
to: displayTo,
|
|
326
|
+
msgId: msgId || null,
|
|
327
|
+
fallbackToAgent: true,
|
|
328
|
+
},
|
|
329
|
+
{ debugOnly: true, debugEnabled: nativeCommandDebugEnabled },
|
|
330
|
+
);
|
|
331
|
+
return buildNativeCommandHandledResult({
|
|
356
332
|
command: command.command,
|
|
357
|
-
accountId,
|
|
358
333
|
sessionKey,
|
|
359
|
-
to: displayTo,
|
|
360
|
-
msgId: msgId || null,
|
|
361
334
|
fallbackToAgent: true,
|
|
362
335
|
});
|
|
363
|
-
return { handled: true, command: command.command, sessionKey, fallbackToAgent: true };
|
|
364
336
|
}
|
|
365
337
|
|
|
366
338
|
logBncrNativeCommandEvent(
|
|
@@ -375,5 +347,8 @@ export async function handleBncrNativeCommand(params: {
|
|
|
375
347
|
},
|
|
376
348
|
{ debugOnly: true, debugEnabled: nativeCommandDebugEnabled },
|
|
377
349
|
);
|
|
378
|
-
return {
|
|
350
|
+
return buildNativeCommandHandledResult({
|
|
351
|
+
command: command.command,
|
|
352
|
+
sessionKey,
|
|
353
|
+
});
|
|
379
354
|
}
|