@xmoxmo/bncr 0.2.6 → 0.2.8
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 +7 -1
- package/index.ts +30 -15
- package/package.json +4 -3
- package/scripts/check-pack.mjs +77 -0
- package/scripts/selfcheck.mjs +10 -0
- package/src/channel.ts +398 -642
- package/src/core/extended-diagnostics.ts +10 -0
- package/src/core/file-ack.ts +9 -0
- package/src/core/file-transfer-payloads.ts +72 -0
- package/src/core/register-trace.ts +79 -0
- package/src/core/targets.ts +10 -1
- package/src/messaging/inbound/commands.ts +20 -10
- package/src/messaging/inbound/context-facts.ts +200 -0
- package/src/messaging/inbound/dispatch.ts +66 -14
- package/src/messaging/inbound/gate.ts +66 -26
- package/src/messaging/inbound/runtime-compat.ts +41 -0
- package/src/messaging/inbound/session-label.ts +7 -7
- package/src/messaging/outbound/durable-message-adapter.ts +107 -0
- package/src/messaging/outbound/durable-queue-adapter.ts +157 -0
- package/src/messaging/outbound/session-route.ts +2 -2
- package/src/openclaw/config-runtime.ts +52 -0
- package/src/openclaw/inbound-session-runtime.ts +94 -0
- package/src/openclaw/ingress-runtime.ts +35 -0
- package/src/openclaw/media-runtime.ts +73 -0
- package/src/openclaw/reply-runtime.ts +104 -0
- package/src/openclaw/routing-runtime.ts +48 -0
- package/src/openclaw/sdk-helpers.ts +20 -0
- package/src/openclaw/session-route-runtime.ts +15 -0
- package/src/plugin/capabilities.ts +8 -0
- package/src/plugin/config.ts +35 -0
- package/src/plugin/gateway-methods.ts +12 -0
- package/src/plugin/gateway-runtime.ts +11 -0
- package/src/plugin/message-policy.ts +4 -0
- package/src/plugin/message-send.ts +13 -0
- package/src/plugin/messaging.ts +142 -0
- package/src/plugin/meta.ts +10 -0
- package/src/plugin/outbound.ts +51 -0
- package/src/plugin/setup.ts +24 -0
- package/src/plugin/status.ts +38 -0
- package/src/runtime/log-dedupe.ts +56 -0
- package/src/runtime/outbound-ack-timeout.ts +96 -0
- package/src/runtime/outbound-flags.ts +81 -0
- package/src/runtime/outbox-transitions.ts +119 -0
- package/src/runtime/status-snapshots.ts +108 -0
- package/src/runtime/status-worker.ts +172 -0
|
@@ -2,6 +2,10 @@ import type { RegisterTraceEntry } from './register-trace.ts';
|
|
|
2
2
|
|
|
3
3
|
type ExtendedDiagnosticsInput = {
|
|
4
4
|
diagnostics: Record<string, any>;
|
|
5
|
+
runtimeSurface?: {
|
|
6
|
+
channel: Record<string, boolean>;
|
|
7
|
+
missing: string[];
|
|
8
|
+
};
|
|
5
9
|
register: {
|
|
6
10
|
bridgeId: string;
|
|
7
11
|
gatewayPid: number;
|
|
@@ -48,6 +52,12 @@ type ExtendedDiagnosticsInput = {
|
|
|
48
52
|
export function buildExtendedDiagnostics(input: ExtendedDiagnosticsInput) {
|
|
49
53
|
return {
|
|
50
54
|
...input.diagnostics,
|
|
55
|
+
runtimeSurface: input.runtimeSurface
|
|
56
|
+
? {
|
|
57
|
+
channel: { ...input.runtimeSurface.channel },
|
|
58
|
+
missing: input.runtimeSurface.missing.slice(),
|
|
59
|
+
}
|
|
60
|
+
: undefined,
|
|
51
61
|
register: {
|
|
52
62
|
...input.register,
|
|
53
63
|
traceRecent: input.register.traceRecent.slice(),
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export function buildFileAckKey(args: {
|
|
2
|
+
transferId: string;
|
|
3
|
+
stage: string;
|
|
4
|
+
chunkIndex?: number;
|
|
5
|
+
}): string {
|
|
6
|
+
const n = Number(args.chunkIndex);
|
|
7
|
+
const idx = Number.isInteger(n) && n >= 0 ? String(n) : '-';
|
|
8
|
+
return `${args.transferId}|${args.stage}|${idx}`;
|
|
9
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { BncrRoute } from './accounts.ts';
|
|
2
|
+
|
|
3
|
+
export function buildFileTransferInitPayload(args: {
|
|
4
|
+
transferId: string;
|
|
5
|
+
sessionKey: string;
|
|
6
|
+
route: BncrRoute;
|
|
7
|
+
fileName: string;
|
|
8
|
+
mimeType?: string;
|
|
9
|
+
fileSize: number;
|
|
10
|
+
chunkSize: number;
|
|
11
|
+
totalChunks: number;
|
|
12
|
+
fileSha256: string;
|
|
13
|
+
ts: number;
|
|
14
|
+
}) {
|
|
15
|
+
return {
|
|
16
|
+
transferId: args.transferId,
|
|
17
|
+
direction: 'oc2bncr' as const,
|
|
18
|
+
sessionKey: args.sessionKey,
|
|
19
|
+
platform: args.route.platform,
|
|
20
|
+
groupId: args.route.groupId,
|
|
21
|
+
userId: args.route.userId,
|
|
22
|
+
fileName: args.fileName,
|
|
23
|
+
mimeType: args.mimeType,
|
|
24
|
+
fileSize: args.fileSize,
|
|
25
|
+
chunkSize: args.chunkSize,
|
|
26
|
+
totalChunks: args.totalChunks,
|
|
27
|
+
fileSha256: args.fileSha256,
|
|
28
|
+
ts: args.ts,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function buildFileTransferChunkPayload(args: {
|
|
33
|
+
transferId: string;
|
|
34
|
+
chunkIndex: number;
|
|
35
|
+
offset: number;
|
|
36
|
+
size: number;
|
|
37
|
+
chunkSha256: string;
|
|
38
|
+
base64: string;
|
|
39
|
+
ts: number;
|
|
40
|
+
}) {
|
|
41
|
+
return {
|
|
42
|
+
transferId: args.transferId,
|
|
43
|
+
chunkIndex: args.chunkIndex,
|
|
44
|
+
offset: args.offset,
|
|
45
|
+
size: args.size,
|
|
46
|
+
chunkSha256: args.chunkSha256,
|
|
47
|
+
base64: args.base64,
|
|
48
|
+
ts: args.ts,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function buildFileTransferAbortPayload(args: {
|
|
53
|
+
transferId: string;
|
|
54
|
+
reason: string;
|
|
55
|
+
ts: number;
|
|
56
|
+
}) {
|
|
57
|
+
return {
|
|
58
|
+
transferId: args.transferId,
|
|
59
|
+
reason: args.reason,
|
|
60
|
+
ts: args.ts,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function buildFileTransferCompletePayload(args: {
|
|
65
|
+
transferId: string;
|
|
66
|
+
ts: number;
|
|
67
|
+
}) {
|
|
68
|
+
return {
|
|
69
|
+
transferId: args.transferId,
|
|
70
|
+
ts: args.ts,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
@@ -33,6 +33,19 @@ export type RegisterTraceSummary = {
|
|
|
33
33
|
likelyStartupFanoutOnly: boolean;
|
|
34
34
|
};
|
|
35
35
|
|
|
36
|
+
export type RegisterDriftSnapshot = {
|
|
37
|
+
capturedAt: number;
|
|
38
|
+
registerCount: number;
|
|
39
|
+
apiGeneration: number;
|
|
40
|
+
postWarmupRegisterCount: number;
|
|
41
|
+
apiInstanceId: string | null;
|
|
42
|
+
registryFingerprint: string | null;
|
|
43
|
+
dominantBucket: string | null;
|
|
44
|
+
sourceBuckets: Record<string, number>;
|
|
45
|
+
traceWindowSize: number;
|
|
46
|
+
traceRecent: Array<Record<string, unknown>>;
|
|
47
|
+
};
|
|
48
|
+
|
|
36
49
|
export function classifyRegisterTrace(stack: string) {
|
|
37
50
|
if (
|
|
38
51
|
stack.includes('prepareSecretsRuntimeSnapshot') ||
|
|
@@ -68,6 +81,72 @@ export function dominantRegisterBucket(sourceBuckets: Record<string, number>) {
|
|
|
68
81
|
return winner;
|
|
69
82
|
}
|
|
70
83
|
|
|
84
|
+
export function buildRegisterTraceEntry(args: {
|
|
85
|
+
ts: number;
|
|
86
|
+
bridgeId: string;
|
|
87
|
+
gatewayPid: number;
|
|
88
|
+
registerCount: number;
|
|
89
|
+
apiGeneration: number;
|
|
90
|
+
apiRebound: boolean;
|
|
91
|
+
apiInstanceId: string | null;
|
|
92
|
+
registryFingerprint: string | null;
|
|
93
|
+
source: string | null;
|
|
94
|
+
pluginVersion: string | null;
|
|
95
|
+
stack: string;
|
|
96
|
+
}): RegisterTraceEntry {
|
|
97
|
+
return {
|
|
98
|
+
ts: args.ts,
|
|
99
|
+
bridgeId: args.bridgeId,
|
|
100
|
+
gatewayPid: args.gatewayPid,
|
|
101
|
+
registerCount: args.registerCount,
|
|
102
|
+
apiGeneration: args.apiGeneration,
|
|
103
|
+
apiRebound: args.apiRebound,
|
|
104
|
+
apiInstanceId: args.apiInstanceId,
|
|
105
|
+
registryFingerprint: args.registryFingerprint,
|
|
106
|
+
source: args.source,
|
|
107
|
+
pluginVersion: args.pluginVersion,
|
|
108
|
+
stack: args.stack,
|
|
109
|
+
stackBucket: classifyRegisterTrace(args.stack),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function appendBoundedRegisterTrace(
|
|
114
|
+
traceRecent: RegisterTraceEntry[],
|
|
115
|
+
trace: RegisterTraceEntry,
|
|
116
|
+
maxEntries = 12,
|
|
117
|
+
) {
|
|
118
|
+
traceRecent.push(trace);
|
|
119
|
+
const cap = Math.max(0, Math.floor(finiteNumberOr(maxEntries, 12)));
|
|
120
|
+
if (cap === 0) {
|
|
121
|
+
traceRecent.splice(0, traceRecent.length);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (traceRecent.length > cap) traceRecent.splice(0, traceRecent.length - cap);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export function buildRegisterDriftSnapshot(args: {
|
|
128
|
+
capturedAt: number;
|
|
129
|
+
registerCount: number;
|
|
130
|
+
apiGeneration: number;
|
|
131
|
+
summary: RegisterTraceSummary;
|
|
132
|
+
apiInstanceId: string | null;
|
|
133
|
+
registryFingerprint: string | null;
|
|
134
|
+
traceRecent: RegisterTraceEntry[];
|
|
135
|
+
}): RegisterDriftSnapshot {
|
|
136
|
+
return {
|
|
137
|
+
capturedAt: args.capturedAt,
|
|
138
|
+
registerCount: args.registerCount,
|
|
139
|
+
apiGeneration: args.apiGeneration,
|
|
140
|
+
postWarmupRegisterCount: args.summary.postWarmupRegisterCount,
|
|
141
|
+
apiInstanceId: args.apiInstanceId,
|
|
142
|
+
registryFingerprint: args.registryFingerprint,
|
|
143
|
+
dominantBucket: args.summary.dominantBucket,
|
|
144
|
+
sourceBuckets: { ...args.summary.sourceBuckets },
|
|
145
|
+
traceWindowSize: args.traceRecent.length,
|
|
146
|
+
traceRecent: args.traceRecent.map((trace) => ({ ...trace })),
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
71
150
|
export function buildRegisterTraceSummary(args: {
|
|
72
151
|
traceRecent: RegisterTraceEntry[];
|
|
73
152
|
firstRegisterAt: number | null;
|
package/src/core/targets.ts
CHANGED
|
@@ -51,8 +51,17 @@ function parseRouteFromStandardDisplayScope(scope: string): BncrRoute | null {
|
|
|
51
51
|
return null;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
function normalizeDisplayScopePrefix(scope: string): string {
|
|
55
55
|
const raw = asString(scope).trim();
|
|
56
|
+
if (!raw) return '';
|
|
57
|
+
if (raw.startsWith('Bncr:')) return raw;
|
|
58
|
+
if (/^bncr[:-]/i.test(raw)) return raw;
|
|
59
|
+
if (!parseRouteFromStandardDisplayScope(raw)) return raw;
|
|
60
|
+
return `Bncr:${raw}`;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function parseRouteFromDisplayScope(scope: string): BncrRoute | null {
|
|
64
|
+
const raw = normalizeDisplayScopePrefix(scope);
|
|
56
65
|
if (!raw) return null;
|
|
57
66
|
|
|
58
67
|
const payload = raw.match(/^Bncr:(.+)$/)?.[1];
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { resolvePinnedMainDmOwnerFromAllowlist } from 'openclaw/plugin-sdk/conversation-runtime';
|
|
2
|
-
import { resolveInboundLastRouteSessionKey } from 'openclaw/plugin-sdk/routing';
|
|
3
1
|
import { emitBncrLogLine } from '../../core/logging.ts';
|
|
4
2
|
import { resolveBncrChannelPolicy } from '../../core/policy.ts';
|
|
5
3
|
import {
|
|
@@ -8,11 +6,22 @@ import {
|
|
|
8
6
|
withTaskSessionKey,
|
|
9
7
|
} from '../../core/targets.ts';
|
|
10
8
|
import { buildBncrReplyConfig } from './reply-config.ts';
|
|
9
|
+
import { resolveBncrChannelInboundRuntime } from './runtime-compat.ts';
|
|
11
10
|
import {
|
|
12
11
|
buildBncrInboundSessionIdentityPatch,
|
|
13
12
|
recordAndPatchBncrInboundSessionEntry,
|
|
14
13
|
wrapBncrInboundRecordSessionLabelCorrection,
|
|
15
14
|
} from './session-label.ts';
|
|
15
|
+
import { dispatchOpenClawReplyWithBufferedBlockDispatcher } from '../../openclaw/reply-runtime.ts';
|
|
16
|
+
import {
|
|
17
|
+
resolveOpenClawAgentRoute,
|
|
18
|
+
resolveOpenClawInboundLastRouteSessionKey,
|
|
19
|
+
} from '../../openclaw/routing-runtime.ts';
|
|
20
|
+
import {
|
|
21
|
+
recordBncrInboundSession,
|
|
22
|
+
resolveBncrInboundSessionStorePath,
|
|
23
|
+
resolveBncrPinnedMainDmOwnerFromAllowlist,
|
|
24
|
+
} from '../../openclaw/inbound-session-runtime.ts';
|
|
16
25
|
|
|
17
26
|
type ParsedInbound = ReturnType<typeof import('./parse.ts')['parseBncrInboundParams']>;
|
|
18
27
|
|
|
@@ -110,7 +119,7 @@ export async function handleBncrNativeCommand(params: {
|
|
|
110
119
|
{ debugOnly: true, debugEnabled: nativeCommandDebugEnabled },
|
|
111
120
|
);
|
|
112
121
|
|
|
113
|
-
const resolvedRoute = api
|
|
122
|
+
const resolvedRoute = resolveOpenClawAgentRoute(api, {
|
|
114
123
|
cfg,
|
|
115
124
|
channel: channelId,
|
|
116
125
|
accountId,
|
|
@@ -137,11 +146,12 @@ export async function handleBncrNativeCommand(params: {
|
|
|
137
146
|
}
|
|
138
147
|
const senderIdForContext = clientId || displayTo;
|
|
139
148
|
const senderDisplayName = clientId ? 'bncr-client' : displayTo;
|
|
140
|
-
const storePath =
|
|
149
|
+
const storePath = resolveBncrInboundSessionStorePath({
|
|
150
|
+
storeConfig: cfg?.session?.store,
|
|
141
151
|
agentId: resolvedRoute.agentId,
|
|
142
152
|
});
|
|
143
153
|
|
|
144
|
-
const ctxPayload = api.
|
|
154
|
+
const ctxPayload = resolveBncrChannelInboundRuntime(api).buildContext({
|
|
145
155
|
channel: channelId,
|
|
146
156
|
provider: channelId,
|
|
147
157
|
surface: channelId,
|
|
@@ -259,13 +269,13 @@ export async function handleBncrNativeCommand(params: {
|
|
|
259
269
|
const channelPolicy = resolveBncrChannelPolicy(cfg?.channels?.bncr || {});
|
|
260
270
|
const pinnedMainDmOwner =
|
|
261
271
|
peer.kind === 'direct'
|
|
262
|
-
?
|
|
272
|
+
? resolveBncrPinnedMainDmOwnerFromAllowlist({
|
|
263
273
|
dmScope: cfg?.session?.dmScope,
|
|
264
274
|
allowFrom: channelPolicy.allowFrom,
|
|
265
275
|
normalizeEntry: (entry: string) => String(entry || '').trim(),
|
|
266
276
|
})
|
|
267
277
|
: null;
|
|
268
|
-
const inboundLastRouteSessionKey =
|
|
278
|
+
const inboundLastRouteSessionKey = resolveOpenClawInboundLastRouteSessionKey({
|
|
269
279
|
route: resolvedRoute,
|
|
270
280
|
sessionKey,
|
|
271
281
|
});
|
|
@@ -282,7 +292,7 @@ export async function handleBncrNativeCommand(params: {
|
|
|
282
292
|
},
|
|
283
293
|
{ debugOnly: true, debugEnabled: nativeCommandDebugEnabled },
|
|
284
294
|
);
|
|
285
|
-
await api.
|
|
295
|
+
await resolveBncrChannelInboundRuntime(api).run({
|
|
286
296
|
channel: channelId,
|
|
287
297
|
accountId,
|
|
288
298
|
raw: parsed,
|
|
@@ -302,7 +312,7 @@ export async function handleBncrNativeCommand(params: {
|
|
|
302
312
|
storePath,
|
|
303
313
|
ctxPayload,
|
|
304
314
|
recordInboundSession: wrapBncrInboundRecordSessionLabelCorrection({
|
|
305
|
-
recordInboundSession:
|
|
315
|
+
recordInboundSession: recordBncrInboundSession,
|
|
306
316
|
expectedLabel: displayTo,
|
|
307
317
|
}),
|
|
308
318
|
record: {
|
|
@@ -330,7 +340,7 @@ export async function handleBncrNativeCommand(params: {
|
|
|
330
340
|
},
|
|
331
341
|
},
|
|
332
342
|
runDispatch: () =>
|
|
333
|
-
api
|
|
343
|
+
dispatchOpenClawReplyWithBufferedBlockDispatcher(api, {
|
|
334
344
|
ctx: ctxPayload,
|
|
335
345
|
cfg: effectiveReply.replyCfg,
|
|
336
346
|
dispatcherOptions: {
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
export type BncrStructuredContextFactsInput = {
|
|
2
|
+
channelId: string;
|
|
3
|
+
accountId: string;
|
|
4
|
+
route: {
|
|
5
|
+
agentId?: string;
|
|
6
|
+
routeSessionKey?: string;
|
|
7
|
+
dispatchSessionKey?: string;
|
|
8
|
+
mainSessionKey?: string;
|
|
9
|
+
};
|
|
10
|
+
conversation: {
|
|
11
|
+
kind: string;
|
|
12
|
+
id: string;
|
|
13
|
+
label: string;
|
|
14
|
+
};
|
|
15
|
+
reply: {
|
|
16
|
+
to: string;
|
|
17
|
+
originatingTo: string;
|
|
18
|
+
};
|
|
19
|
+
sender: {
|
|
20
|
+
id: string;
|
|
21
|
+
displayName?: string;
|
|
22
|
+
};
|
|
23
|
+
message: {
|
|
24
|
+
id?: string | null;
|
|
25
|
+
rawBody: string;
|
|
26
|
+
bodyForAgent?: string;
|
|
27
|
+
commandBody?: string;
|
|
28
|
+
envelopeBody?: string;
|
|
29
|
+
};
|
|
30
|
+
media?: Array<{
|
|
31
|
+
path: string;
|
|
32
|
+
contentType?: string;
|
|
33
|
+
kind?: string;
|
|
34
|
+
messageId?: string;
|
|
35
|
+
}>;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export function buildBncrStructuredContextFacts(input: BncrStructuredContextFactsInput) {
|
|
39
|
+
const rawBody = input.message.rawBody;
|
|
40
|
+
return {
|
|
41
|
+
channel: {
|
|
42
|
+
id: input.channelId,
|
|
43
|
+
accountId: input.accountId,
|
|
44
|
+
},
|
|
45
|
+
route: {
|
|
46
|
+
agentId: input.route.agentId,
|
|
47
|
+
routeSessionKey: input.route.routeSessionKey,
|
|
48
|
+
dispatchSessionKey: input.route.dispatchSessionKey,
|
|
49
|
+
mainSessionKey: input.route.mainSessionKey,
|
|
50
|
+
},
|
|
51
|
+
conversation: {
|
|
52
|
+
kind: input.conversation.kind,
|
|
53
|
+
id: input.conversation.id,
|
|
54
|
+
label: input.conversation.label,
|
|
55
|
+
},
|
|
56
|
+
reply: {
|
|
57
|
+
to: input.reply.to,
|
|
58
|
+
originatingTo: input.reply.originatingTo,
|
|
59
|
+
},
|
|
60
|
+
sender: {
|
|
61
|
+
id: input.sender.id,
|
|
62
|
+
displayName: input.sender.displayName || input.sender.id,
|
|
63
|
+
},
|
|
64
|
+
message: {
|
|
65
|
+
id: input.message.id || undefined,
|
|
66
|
+
rawBody,
|
|
67
|
+
bodyForAgent: input.message.bodyForAgent ?? rawBody,
|
|
68
|
+
commandBody: input.message.commandBody ?? rawBody,
|
|
69
|
+
envelopeBody: input.message.envelopeBody,
|
|
70
|
+
},
|
|
71
|
+
media: (input.media || []).map((item) => ({
|
|
72
|
+
path: item.path,
|
|
73
|
+
contentType: item.contentType,
|
|
74
|
+
kind: item.kind,
|
|
75
|
+
messageId: item.messageId,
|
|
76
|
+
})),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Keep this payload intentionally small: OpenClaw already renders standard
|
|
81
|
+
// conversation/sender/message metadata as untrusted context. Only include
|
|
82
|
+
// bncr-specific facts that are not otherwise visible to the model, so normal
|
|
83
|
+
// text turns do not get a duplicate "Bncr inbound context" JSON block.
|
|
84
|
+
export function buildBncrPromptVisibleContextFacts(
|
|
85
|
+
facts: ReturnType<typeof buildBncrStructuredContextFacts>,
|
|
86
|
+
) {
|
|
87
|
+
const result: {
|
|
88
|
+
reply?: {
|
|
89
|
+
to: string;
|
|
90
|
+
originatingTo: string;
|
|
91
|
+
};
|
|
92
|
+
media?: Array<{
|
|
93
|
+
contentType?: string;
|
|
94
|
+
kind?: string;
|
|
95
|
+
messageId?: string;
|
|
96
|
+
}>;
|
|
97
|
+
} = {};
|
|
98
|
+
|
|
99
|
+
if (facts.reply.originatingTo !== facts.reply.to) {
|
|
100
|
+
result.reply = {
|
|
101
|
+
to: facts.reply.to,
|
|
102
|
+
originatingTo: facts.reply.originatingTo,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (facts.media.length > 0) {
|
|
107
|
+
result.media = facts.media.map((item) => ({
|
|
108
|
+
contentType: item.contentType,
|
|
109
|
+
kind: item.kind,
|
|
110
|
+
messageId: item.messageId,
|
|
111
|
+
}));
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return result;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function inferBncrStructuredMediaKind(contentType: string | undefined) {
|
|
118
|
+
if (contentType?.startsWith('image/')) return 'image';
|
|
119
|
+
if (contentType?.startsWith('video/')) return 'video';
|
|
120
|
+
if (contentType?.startsWith('audio/')) return 'audio';
|
|
121
|
+
return 'document';
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export type BncrStructuredContextFactsFromInboundPartsInput = {
|
|
125
|
+
channelId: string;
|
|
126
|
+
parsed: {
|
|
127
|
+
accountId: string;
|
|
128
|
+
peer: {
|
|
129
|
+
kind: string;
|
|
130
|
+
id: string;
|
|
131
|
+
};
|
|
132
|
+
clientId?: string;
|
|
133
|
+
msgId?: string;
|
|
134
|
+
mimeType?: string;
|
|
135
|
+
};
|
|
136
|
+
resolution: {
|
|
137
|
+
chatType: string;
|
|
138
|
+
canonicalTo: string;
|
|
139
|
+
originatingTo: string;
|
|
140
|
+
resolvedRoute: {
|
|
141
|
+
agentId?: string;
|
|
142
|
+
sessionKey?: string;
|
|
143
|
+
mainSessionKey?: string;
|
|
144
|
+
};
|
|
145
|
+
dispatchSessionKey?: string;
|
|
146
|
+
};
|
|
147
|
+
prepared: {
|
|
148
|
+
rawBody: string;
|
|
149
|
+
body?: string;
|
|
150
|
+
mediaPath?: string | null;
|
|
151
|
+
};
|
|
152
|
+
senderIdForContext: string;
|
|
153
|
+
senderDisplayName?: string;
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
export function buildBncrStructuredContextFactsFromInboundParts(
|
|
157
|
+
input: BncrStructuredContextFactsFromInboundPartsInput,
|
|
158
|
+
) {
|
|
159
|
+
const mediaPath = input.prepared.mediaPath || undefined;
|
|
160
|
+
return buildBncrStructuredContextFacts({
|
|
161
|
+
channelId: input.channelId,
|
|
162
|
+
accountId: input.parsed.accountId,
|
|
163
|
+
route: {
|
|
164
|
+
agentId: input.resolution.resolvedRoute.agentId,
|
|
165
|
+
routeSessionKey: input.resolution.resolvedRoute.sessionKey,
|
|
166
|
+
dispatchSessionKey: input.resolution.dispatchSessionKey,
|
|
167
|
+
mainSessionKey: input.resolution.resolvedRoute.mainSessionKey,
|
|
168
|
+
},
|
|
169
|
+
conversation: {
|
|
170
|
+
kind: input.resolution.chatType,
|
|
171
|
+
id: input.parsed.peer.id,
|
|
172
|
+
label: input.resolution.canonicalTo,
|
|
173
|
+
},
|
|
174
|
+
reply: {
|
|
175
|
+
to: input.resolution.canonicalTo,
|
|
176
|
+
originatingTo: input.resolution.originatingTo,
|
|
177
|
+
},
|
|
178
|
+
sender: {
|
|
179
|
+
id: input.senderIdForContext,
|
|
180
|
+
displayName: input.senderDisplayName,
|
|
181
|
+
},
|
|
182
|
+
message: {
|
|
183
|
+
id: input.parsed.msgId,
|
|
184
|
+
rawBody: input.prepared.rawBody,
|
|
185
|
+
bodyForAgent: input.prepared.rawBody,
|
|
186
|
+
commandBody: input.prepared.rawBody,
|
|
187
|
+
envelopeBody: input.prepared.body,
|
|
188
|
+
},
|
|
189
|
+
media: mediaPath
|
|
190
|
+
? [
|
|
191
|
+
{
|
|
192
|
+
path: mediaPath,
|
|
193
|
+
contentType: input.parsed.mimeType,
|
|
194
|
+
kind: inferBncrStructuredMediaKind(input.parsed.mimeType),
|
|
195
|
+
messageId: input.parsed.msgId,
|
|
196
|
+
},
|
|
197
|
+
]
|
|
198
|
+
: [],
|
|
199
|
+
});
|
|
200
|
+
}
|