@xmoxmo/bncr 0.4.6 → 0.4.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 +8 -0
- package/package.json +1 -1
- package/src/channel.ts +41 -2
- package/src/core/targets.ts +106 -17
- package/src/messaging/inbound/commands.ts +421 -51
- package/src/messaging/inbound/context-facts.ts +126 -14
- package/src/messaging/inbound/contracts.ts +24 -0
- package/src/messaging/inbound/dispatch-prep.ts +214 -39
- package/src/messaging/inbound/dispatch.ts +71 -5
- package/src/messaging/inbound/gate.ts +56 -86
- package/src/messaging/inbound/group-history.ts +189 -0
- package/src/messaging/inbound/native-command-runtime.ts +77 -61
- package/src/messaging/inbound/native-command.ts +192 -8
- package/src/messaging/inbound/parse.ts +113 -8
- package/src/messaging/inbound/reply-dispatch-serial.ts +62 -0
- package/src/messaging/inbound/reply-dispatch.ts +252 -77
- package/src/messaging/inbound/scene-admin.ts +300 -0
- package/src/messaging/inbound/session-label.ts +122 -13
- package/src/messaging/inbound/session-meta-task.ts +17 -0
- package/src/messaging/inbound/turn-context.ts +184 -71
- package/src/openclaw/channel-runtime-contracts.ts +1 -0
- package/src/plugin/channel-components.ts +35 -1
- package/src/plugin/channel-inbound-helpers.ts +9 -2
- package/src/plugin/channel-runtime-builders-delivery.ts +24 -1
- package/src/plugin/channel-runtime-types.ts +42 -0
- package/src/plugin/file-inbound-init.ts +27 -12
- package/src/plugin/file-inbound-runtime.ts +2 -0
- package/src/plugin/inbound-acceptance.ts +82 -1
- package/src/plugin/inbound-handlers.ts +97 -2
- package/src/plugin/inbound-surface-handlers-group.ts +16 -0
- package/src/plugin/messaging.ts +22 -5
- package/src/plugin/scene-registry.ts +171 -0
- package/src/plugin/state-store.ts +133 -0
- package/src/plugin/state-transient-runtime-group.ts +5 -0
- package/src/plugin/target-runtime.ts +2 -2
|
@@ -5,6 +5,37 @@ import {
|
|
|
5
5
|
updateBncrSessionStoreEntry,
|
|
6
6
|
} from '../../openclaw/inbound-session-runtime.ts';
|
|
7
7
|
|
|
8
|
+
function formatBncrSessionLabel(displayTo: string): string {
|
|
9
|
+
const raw = String(displayTo || '').trim();
|
|
10
|
+
const parts = raw.split(':');
|
|
11
|
+
if (parts.length === 4 && parts[0] === 'Bncr') {
|
|
12
|
+
const [, platform, groupId, userId] = parts;
|
|
13
|
+
if (platform && groupId && groupId !== '0') return `Bncr:${platform}:Group:${groupId}`;
|
|
14
|
+
if (platform && userId && userId !== '0') return `Bncr:${platform}:User:${userId}`;
|
|
15
|
+
}
|
|
16
|
+
return raw;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function formatBncrSessionRouteTarget(displayTo: string): string {
|
|
20
|
+
const raw = String(displayTo || '').trim();
|
|
21
|
+
const parts = raw.split(':');
|
|
22
|
+
if (parts.length === 4 && parts[0] === 'Bncr') {
|
|
23
|
+
const [, platform, groupId, userId] = parts;
|
|
24
|
+
if (platform && groupId && groupId !== '0') return `Bncr:${platform}:${groupId}:0`;
|
|
25
|
+
if (platform && userId && userId !== '0') return `Bncr:${platform}:0:${userId}`;
|
|
26
|
+
}
|
|
27
|
+
return raw;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function formatBncrSessionGroupKey(displayTo: string): string | null {
|
|
31
|
+
const raw = String(displayTo || '').trim();
|
|
32
|
+
const parts = raw.split(':');
|
|
33
|
+
if (parts.length !== 4 || parts[0] !== 'Bncr') return null;
|
|
34
|
+
const [, platform, groupId] = parts;
|
|
35
|
+
if (!platform || !groupId || groupId === '0') return null;
|
|
36
|
+
return `${platform.toLowerCase()}:${groupId}`;
|
|
37
|
+
}
|
|
38
|
+
|
|
8
39
|
type RecordInboundSessionFn = (args: {
|
|
9
40
|
storePath?: string;
|
|
10
41
|
sessionKey?: string;
|
|
@@ -21,30 +52,35 @@ export function buildBncrInboundSessionIdentityPatch(args: {
|
|
|
21
52
|
senderId: string;
|
|
22
53
|
}) {
|
|
23
54
|
const { channelId, accountId, chatType, displayTo, senderId } = args;
|
|
55
|
+
const displayLabel = formatBncrSessionLabel(displayTo);
|
|
56
|
+
const routeTarget = formatBncrSessionRouteTarget(displayTo);
|
|
57
|
+
const groupKey = chatType === 'group' ? formatBncrSessionGroupKey(displayTo) : null;
|
|
24
58
|
return {
|
|
25
|
-
label:
|
|
59
|
+
label: displayLabel,
|
|
60
|
+
displayName: displayLabel,
|
|
26
61
|
channel: channelId,
|
|
27
62
|
chatType,
|
|
63
|
+
...(groupKey ? { groupId: groupKey } : {}),
|
|
28
64
|
origin: {
|
|
29
|
-
label:
|
|
65
|
+
label: displayLabel,
|
|
30
66
|
provider: channelId,
|
|
31
67
|
surface: channelId,
|
|
32
68
|
chatType,
|
|
33
69
|
from: senderId,
|
|
34
|
-
to:
|
|
70
|
+
to: routeTarget,
|
|
35
71
|
accountId,
|
|
36
72
|
},
|
|
37
73
|
deliveryContext: {
|
|
38
74
|
channel: channelId,
|
|
39
|
-
to:
|
|
75
|
+
to: routeTarget,
|
|
40
76
|
accountId,
|
|
41
77
|
},
|
|
42
78
|
route: {
|
|
43
79
|
channel: channelId,
|
|
44
80
|
accountId,
|
|
45
|
-
target: { to:
|
|
81
|
+
target: { to: routeTarget },
|
|
46
82
|
},
|
|
47
|
-
lastTo:
|
|
83
|
+
lastTo: routeTarget,
|
|
48
84
|
};
|
|
49
85
|
}
|
|
50
86
|
|
|
@@ -56,20 +92,93 @@ function normalizeNonEmptyString(value: unknown): string | null {
|
|
|
56
92
|
export async function correctBncrInboundSessionLabel(args: {
|
|
57
93
|
storePath: string;
|
|
58
94
|
sessionKey: string;
|
|
59
|
-
|
|
95
|
+
expectedPatch: Record<string, unknown>;
|
|
60
96
|
}) {
|
|
61
97
|
const storePath = normalizeNonEmptyString(args.storePath);
|
|
62
98
|
const sessionKey = normalizeNonEmptyString(args.sessionKey);
|
|
63
|
-
|
|
64
|
-
|
|
99
|
+
if (!storePath || !sessionKey) return;
|
|
100
|
+
|
|
101
|
+
const expectedPatch = args.expectedPatch;
|
|
102
|
+
const expectedLabel = normalizeNonEmptyString(expectedPatch.label);
|
|
103
|
+
const expectedDisplayName = normalizeNonEmptyString(expectedPatch.displayName);
|
|
104
|
+
const expectedGroupId = normalizeNonEmptyString(expectedPatch.groupId);
|
|
105
|
+
const expectedOriginTo = normalizeNonEmptyString(
|
|
106
|
+
(expectedPatch.origin as { to?: unknown } | undefined)?.to,
|
|
107
|
+
);
|
|
108
|
+
const expectedDeliveryTo = normalizeNonEmptyString(
|
|
109
|
+
(expectedPatch.deliveryContext as { to?: unknown } | undefined)?.to,
|
|
110
|
+
);
|
|
111
|
+
const expectedRouteTo = normalizeNonEmptyString(
|
|
112
|
+
(
|
|
113
|
+
(expectedPatch.route as { target?: { to?: unknown } } | undefined)?.target as
|
|
114
|
+
| { to?: unknown }
|
|
115
|
+
| undefined
|
|
116
|
+
)?.to,
|
|
117
|
+
);
|
|
118
|
+
const expectedLastTo = normalizeNonEmptyString(expectedPatch.lastTo);
|
|
119
|
+
if (
|
|
120
|
+
!expectedLabel ||
|
|
121
|
+
!expectedDisplayName ||
|
|
122
|
+
!expectedOriginTo ||
|
|
123
|
+
!expectedDeliveryTo ||
|
|
124
|
+
!expectedRouteTo ||
|
|
125
|
+
!expectedLastTo
|
|
126
|
+
)
|
|
127
|
+
return;
|
|
65
128
|
|
|
66
129
|
try {
|
|
67
130
|
await updateBncrSessionStoreEntry({
|
|
68
131
|
storePath,
|
|
69
132
|
sessionKey,
|
|
70
133
|
update: (entry: SessionStoreEntryLike) => {
|
|
71
|
-
|
|
72
|
-
|
|
134
|
+
const origin =
|
|
135
|
+
entry?.origin && typeof entry.origin === 'object'
|
|
136
|
+
? (entry.origin as Record<string, unknown>)
|
|
137
|
+
: {};
|
|
138
|
+
const deliveryContext =
|
|
139
|
+
entry?.deliveryContext && typeof entry.deliveryContext === 'object'
|
|
140
|
+
? (entry.deliveryContext as Record<string, unknown>)
|
|
141
|
+
: {};
|
|
142
|
+
const route =
|
|
143
|
+
entry?.route && typeof entry.route === 'object'
|
|
144
|
+
? (entry.route as Record<string, unknown>)
|
|
145
|
+
: {};
|
|
146
|
+
const routeTarget =
|
|
147
|
+
route.target && typeof route.target === 'object'
|
|
148
|
+
? (route.target as Record<string, unknown>)
|
|
149
|
+
: {};
|
|
150
|
+
|
|
151
|
+
const unchanged =
|
|
152
|
+
entry?.label === expectedLabel &&
|
|
153
|
+
entry?.displayName === expectedDisplayName &&
|
|
154
|
+
normalizeNonEmptyString(entry?.groupId) === expectedGroupId &&
|
|
155
|
+
normalizeNonEmptyString(origin.to) === expectedOriginTo &&
|
|
156
|
+
normalizeNonEmptyString(deliveryContext.to) === expectedDeliveryTo &&
|
|
157
|
+
normalizeNonEmptyString(routeTarget.to) === expectedRouteTo &&
|
|
158
|
+
normalizeNonEmptyString(entry?.lastTo) === expectedLastTo;
|
|
159
|
+
if (unchanged) return null;
|
|
160
|
+
|
|
161
|
+
return {
|
|
162
|
+
...(expectedGroupId ? { groupId: expectedGroupId } : {}),
|
|
163
|
+
label: expectedLabel,
|
|
164
|
+
displayName: expectedDisplayName,
|
|
165
|
+
origin: {
|
|
166
|
+
...origin,
|
|
167
|
+
...(expectedPatch.origin as Record<string, unknown>),
|
|
168
|
+
},
|
|
169
|
+
deliveryContext: {
|
|
170
|
+
...deliveryContext,
|
|
171
|
+
...(expectedPatch.deliveryContext as Record<string, unknown>),
|
|
172
|
+
},
|
|
173
|
+
route: {
|
|
174
|
+
...route,
|
|
175
|
+
...(expectedPatch.route as Record<string, unknown>),
|
|
176
|
+
target: {
|
|
177
|
+
to: expectedRouteTo,
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
lastTo: expectedLastTo,
|
|
181
|
+
};
|
|
73
182
|
},
|
|
74
183
|
});
|
|
75
184
|
} catch (err) {
|
|
@@ -108,7 +217,7 @@ export async function recordAndPatchBncrInboundSessionEntry(args: {
|
|
|
108
217
|
|
|
109
218
|
export function wrapBncrInboundRecordSessionLabelCorrection(args: {
|
|
110
219
|
recordInboundSession: RecordInboundSessionFn;
|
|
111
|
-
|
|
220
|
+
expectedPatch: Record<string, unknown>;
|
|
112
221
|
}): RecordInboundSessionFn {
|
|
113
222
|
return async (recordArgs) => {
|
|
114
223
|
const result = await args.recordInboundSession(recordArgs);
|
|
@@ -116,7 +225,7 @@ export function wrapBncrInboundRecordSessionLabelCorrection(args: {
|
|
|
116
225
|
await correctBncrInboundSessionLabel({
|
|
117
226
|
storePath: recordArgs.storePath,
|
|
118
227
|
sessionKey: recordArgs.sessionKey,
|
|
119
|
-
|
|
228
|
+
expectedPatch: args.expectedPatch,
|
|
120
229
|
});
|
|
121
230
|
return result;
|
|
122
231
|
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export function createBncrSessionMetaTaskBarrier() {
|
|
2
|
+
const pending = new Set<Promise<unknown>>();
|
|
3
|
+
|
|
4
|
+
return {
|
|
5
|
+
track(task: Promise<unknown>) {
|
|
6
|
+
if (!task || typeof task.then !== 'function') return;
|
|
7
|
+
pending.add(task);
|
|
8
|
+
void task.finally(() => {
|
|
9
|
+
pending.delete(task);
|
|
10
|
+
});
|
|
11
|
+
},
|
|
12
|
+
async wait() {
|
|
13
|
+
if (pending.size === 0) return;
|
|
14
|
+
await Promise.allSettled([...pending]);
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
}
|
|
@@ -1,41 +1,93 @@
|
|
|
1
|
+
import { readBncrSessionUpdatedAt } from '../../openclaw/inbound-session-runtime.ts';
|
|
2
|
+
import { resolveOpenClawEnvelopeFormatOptions } from '../../openclaw/reply-runtime.ts';
|
|
1
3
|
import {
|
|
2
4
|
buildBncrPromptVisibleContextFacts,
|
|
3
5
|
buildBncrStructuredContextFactsFromInboundParts,
|
|
4
6
|
} from './context-facts.ts';
|
|
5
|
-
import type { BncrInboundApi, BncrInboundContextPayload } from './contracts.ts';
|
|
7
|
+
import type { BncrInboundApi, BncrInboundConfig, BncrInboundContextPayload } from './contracts.ts';
|
|
6
8
|
import type {
|
|
7
9
|
BncrInboundConversationResolution,
|
|
8
10
|
BncrPreparedInboundSessionContext,
|
|
9
11
|
ParsedInbound,
|
|
10
12
|
} from './dispatch-prep.ts';
|
|
13
|
+
import {
|
|
14
|
+
type BncrGroupHistoryMap,
|
|
15
|
+
buildBncrInboundHistory,
|
|
16
|
+
buildBncrPendingGroupContext,
|
|
17
|
+
} from './group-history.ts';
|
|
11
18
|
import { resolveBncrChannelInboundRuntime } from './runtime-compat.ts';
|
|
12
19
|
|
|
20
|
+
function parseSlashCommandName(body: string): string | undefined {
|
|
21
|
+
const raw = String(body || '').trim();
|
|
22
|
+
if (!raw.startsWith('/')) return undefined;
|
|
23
|
+
return raw.slice(1).split(/\s+/, 1)[0]?.split('@', 1)[0] || undefined;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function applyBncrLegacyCommandFields(args: {
|
|
27
|
+
ctx: BncrInboundContextPayload;
|
|
28
|
+
channelId: string;
|
|
29
|
+
senderIdForContext: string;
|
|
30
|
+
resolution: BncrInboundConversationResolution;
|
|
31
|
+
rawBody: string;
|
|
32
|
+
ownerAllowFrom?: string[];
|
|
33
|
+
isAuthorizedTextCommand: boolean;
|
|
34
|
+
}) {
|
|
35
|
+
const { ctx, channelId, senderIdForContext, resolution, rawBody, ownerAllowFrom } = args;
|
|
36
|
+
ctx.From = senderIdForContext;
|
|
37
|
+
ctx.To = resolution.canonicalTo;
|
|
38
|
+
ctx.SenderId = senderIdForContext;
|
|
39
|
+
ctx.OriginatingChannel = channelId;
|
|
40
|
+
if (ownerAllowFrom?.length) ctx.OwnerAllowFrom = ownerAllowFrom;
|
|
41
|
+
if (args.isAuthorizedTextCommand) {
|
|
42
|
+
ctx.CommandAuthorized = true;
|
|
43
|
+
ctx.CommandSource = 'text';
|
|
44
|
+
ctx.CommandTurn = {
|
|
45
|
+
kind: 'text-slash',
|
|
46
|
+
source: 'text',
|
|
47
|
+
authorized: true,
|
|
48
|
+
commandName: parseSlashCommandName(rawBody),
|
|
49
|
+
body: rawBody,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
return ctx;
|
|
53
|
+
}
|
|
54
|
+
|
|
13
55
|
export function buildBncrInboundTurnContext(args: {
|
|
14
56
|
api: BncrInboundApi;
|
|
57
|
+
cfg: BncrInboundConfig;
|
|
15
58
|
channelId: string;
|
|
16
59
|
parsed: ParsedInbound;
|
|
17
60
|
msgId?: string | null;
|
|
18
|
-
mimeType?: string;
|
|
19
|
-
mediaPath?: string;
|
|
20
61
|
peer: ParsedInbound['peer'];
|
|
21
62
|
senderIdForContext: string;
|
|
22
63
|
senderDisplayName: string;
|
|
64
|
+
ownerAllowFrom?: string[];
|
|
65
|
+
bridgeSenderId?: string;
|
|
66
|
+
bridgeSenderName?: string;
|
|
23
67
|
resolution: BncrInboundConversationResolution;
|
|
24
68
|
prepared: BncrPreparedInboundSessionContext;
|
|
69
|
+
groupHistories: BncrGroupHistoryMap;
|
|
70
|
+
shouldDispatch: boolean;
|
|
25
71
|
}): BncrInboundContextPayload | Promise<BncrInboundContextPayload> {
|
|
26
72
|
const {
|
|
27
73
|
api,
|
|
74
|
+
cfg,
|
|
28
75
|
channelId,
|
|
29
76
|
parsed,
|
|
30
77
|
msgId,
|
|
31
|
-
mimeType,
|
|
32
|
-
mediaPath,
|
|
33
78
|
peer,
|
|
34
79
|
senderIdForContext,
|
|
35
80
|
senderDisplayName,
|
|
81
|
+
ownerAllowFrom,
|
|
82
|
+
bridgeSenderId,
|
|
83
|
+
bridgeSenderName,
|
|
36
84
|
resolution,
|
|
37
85
|
prepared,
|
|
86
|
+
groupHistories,
|
|
87
|
+
shouldDispatch,
|
|
38
88
|
} = args;
|
|
89
|
+
const senderIsOwner = parsed.isAdmin === true || Boolean(ownerAllowFrom?.length);
|
|
90
|
+
const senderIsAuthorized = senderIsOwner;
|
|
39
91
|
const structuredContextFacts = buildBncrStructuredContextFactsFromInboundParts({
|
|
40
92
|
channelId,
|
|
41
93
|
parsed,
|
|
@@ -43,11 +95,14 @@ export function buildBncrInboundTurnContext(args: {
|
|
|
43
95
|
prepared: {
|
|
44
96
|
rawBody: prepared.rawBody,
|
|
45
97
|
body: prepared.body,
|
|
46
|
-
|
|
47
|
-
mediaContentType: mimeType,
|
|
98
|
+
mediaItems: prepared.mediaItems,
|
|
48
99
|
},
|
|
49
100
|
senderIdForContext,
|
|
50
101
|
senderDisplayName,
|
|
102
|
+
bridgeSenderId,
|
|
103
|
+
bridgeSenderName,
|
|
104
|
+
senderIsOwner,
|
|
105
|
+
senderIsAuthorized,
|
|
51
106
|
});
|
|
52
107
|
const promptVisibleContextFacts = buildBncrPromptVisibleContextFacts(structuredContextFacts);
|
|
53
108
|
const supplementalUntrustedContext = Object.keys(promptVisibleContextFacts).length
|
|
@@ -60,72 +115,130 @@ export function buildBncrInboundTurnContext(args: {
|
|
|
60
115
|
},
|
|
61
116
|
]
|
|
62
117
|
: [];
|
|
118
|
+
const platformWantsReply = parsed.shouldRespond === true;
|
|
119
|
+
const wasMentioned = parsed.isBotMentioned === true || platformWantsReply;
|
|
120
|
+
const isAuthorizedTextCommand = Boolean(ownerAllowFrom?.length);
|
|
121
|
+
const bodyForAgent =
|
|
122
|
+
shouldDispatch && parsed.peer.kind === 'group'
|
|
123
|
+
? buildBncrPendingGroupContext({
|
|
124
|
+
api,
|
|
125
|
+
historyMap: groupHistories,
|
|
126
|
+
parsed,
|
|
127
|
+
channelLabel: resolution.canonicalTo,
|
|
128
|
+
currentTimestamp: Date.now(),
|
|
129
|
+
previousTimestamp: readBncrSessionUpdatedAt(api, {
|
|
130
|
+
storePath: prepared.storePath,
|
|
131
|
+
sessionKey: resolution.dispatchSessionKey,
|
|
132
|
+
}),
|
|
133
|
+
envelope: resolveOpenClawEnvelopeFormatOptions(api, cfg),
|
|
134
|
+
currentMessage: prepared.body,
|
|
135
|
+
})
|
|
136
|
+
: prepared.body;
|
|
137
|
+
const inboundHistory =
|
|
138
|
+
shouldDispatch && parsed.peer.kind === 'group'
|
|
139
|
+
? buildBncrInboundHistory({ historyMap: groupHistories, parsed })
|
|
140
|
+
: undefined;
|
|
63
141
|
|
|
64
|
-
return
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
label: resolution.canonicalTo,
|
|
81
|
-
routePeer: {
|
|
82
|
-
kind: peer.kind,
|
|
142
|
+
return Promise.resolve(
|
|
143
|
+
resolveBncrChannelInboundRuntime(api).buildContext({
|
|
144
|
+
channel: channelId,
|
|
145
|
+
provider: channelId,
|
|
146
|
+
surface: channelId,
|
|
147
|
+
accountId: resolution.accountId,
|
|
148
|
+
messageId: msgId,
|
|
149
|
+
timestamp: Date.now(),
|
|
150
|
+
from: senderIdForContext,
|
|
151
|
+
sender: {
|
|
152
|
+
id: senderIdForContext,
|
|
153
|
+
name: senderDisplayName,
|
|
154
|
+
username: parsed.userName || senderDisplayName,
|
|
155
|
+
},
|
|
156
|
+
conversation: {
|
|
157
|
+
kind: resolution.chatType,
|
|
83
158
|
id: peer.id,
|
|
159
|
+
label: resolution.canonicalTo,
|
|
160
|
+
routePeer: {
|
|
161
|
+
kind: peer.kind,
|
|
162
|
+
id: peer.id,
|
|
163
|
+
},
|
|
84
164
|
},
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
165
|
+
route: {
|
|
166
|
+
agentId: resolution.resolvedRoute.agentId,
|
|
167
|
+
accountId: resolution.accountId,
|
|
168
|
+
routeSessionKey: resolution.resolvedRoute.sessionKey,
|
|
169
|
+
dispatchSessionKey: resolution.dispatchSessionKey,
|
|
170
|
+
mainSessionKey: resolution.resolvedRoute.mainSessionKey,
|
|
171
|
+
},
|
|
172
|
+
reply: {
|
|
173
|
+
to: resolution.canonicalTo,
|
|
174
|
+
originatingTo: resolution.originatingTo,
|
|
175
|
+
},
|
|
176
|
+
message: {
|
|
177
|
+
inboundEventKind: 'user_request',
|
|
178
|
+
body: prepared.body,
|
|
179
|
+
rawBody: prepared.rawBody,
|
|
180
|
+
bodyForAgent,
|
|
181
|
+
inboundHistory,
|
|
182
|
+
commandBody: prepared.rawBody,
|
|
183
|
+
envelopeFrom: resolution.originatingTo,
|
|
184
|
+
senderLabel: senderDisplayName,
|
|
185
|
+
},
|
|
186
|
+
...(isAuthorizedTextCommand
|
|
187
|
+
? {
|
|
188
|
+
commandTurn: {
|
|
189
|
+
kind: 'text-slash' as const,
|
|
190
|
+
source: 'text' as const,
|
|
191
|
+
authorized: true,
|
|
192
|
+
commandName: parseSlashCommandName(prepared.rawBody),
|
|
193
|
+
body: prepared.rawBody,
|
|
194
|
+
},
|
|
195
|
+
}
|
|
196
|
+
: {}),
|
|
197
|
+
media:
|
|
198
|
+
prepared.mediaItems.length > 0
|
|
199
|
+
? prepared.mediaItems.map((item) => ({
|
|
200
|
+
path: item.path,
|
|
201
|
+
contentType: item.contentType,
|
|
202
|
+
kind: item.kind,
|
|
203
|
+
messageId: msgId ?? undefined,
|
|
204
|
+
}))
|
|
205
|
+
: [],
|
|
206
|
+
access: {
|
|
207
|
+
mentions: {
|
|
208
|
+
canDetectMention: true,
|
|
209
|
+
wasMentioned,
|
|
210
|
+
effectiveWasMentioned: wasMentioned,
|
|
211
|
+
},
|
|
212
|
+
...(isAuthorizedTextCommand
|
|
213
|
+
? {
|
|
214
|
+
commands: {
|
|
215
|
+
authorized: true,
|
|
216
|
+
allowTextCommands: true,
|
|
217
|
+
useAccessGroups: false,
|
|
218
|
+
authorizers: [],
|
|
219
|
+
},
|
|
220
|
+
}
|
|
221
|
+
: {}),
|
|
222
|
+
},
|
|
223
|
+
supplemental: {
|
|
224
|
+
untrustedContext: supplementalUntrustedContext,
|
|
225
|
+
},
|
|
226
|
+
extra: {
|
|
227
|
+
OriginatingChannel: channelId,
|
|
228
|
+
...(ownerAllowFrom?.length ? { OwnerAllowFrom: ownerAllowFrom } : {}),
|
|
229
|
+
BncrStructuredContextFacts: structuredContextFacts,
|
|
230
|
+
StructuredContextFacts: structuredContextFacts,
|
|
231
|
+
},
|
|
232
|
+
}),
|
|
233
|
+
).then((ctx) =>
|
|
234
|
+
applyBncrLegacyCommandFields({
|
|
235
|
+
ctx,
|
|
236
|
+
channelId,
|
|
237
|
+
senderIdForContext,
|
|
238
|
+
resolution,
|
|
100
239
|
rawBody: prepared.rawBody,
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
},
|
|
106
|
-
media: mediaPath
|
|
107
|
-
? [
|
|
108
|
-
{
|
|
109
|
-
path: mediaPath,
|
|
110
|
-
contentType: mimeType,
|
|
111
|
-
kind: mimeType?.startsWith('image/')
|
|
112
|
-
? 'image'
|
|
113
|
-
: mimeType?.startsWith('video/')
|
|
114
|
-
? 'video'
|
|
115
|
-
: mimeType?.startsWith('audio/')
|
|
116
|
-
? 'audio'
|
|
117
|
-
: 'document',
|
|
118
|
-
messageId: msgId ?? undefined,
|
|
119
|
-
},
|
|
120
|
-
]
|
|
121
|
-
: [],
|
|
122
|
-
supplemental: {
|
|
123
|
-
untrustedContext: supplementalUntrustedContext,
|
|
124
|
-
},
|
|
125
|
-
extra: {
|
|
126
|
-
OriginatingChannel: channelId,
|
|
127
|
-
BncrStructuredContextFacts: structuredContextFacts,
|
|
128
|
-
StructuredContextFacts: structuredContextFacts,
|
|
129
|
-
},
|
|
130
|
-
});
|
|
240
|
+
ownerAllowFrom,
|
|
241
|
+
isAuthorizedTextCommand,
|
|
242
|
+
}),
|
|
243
|
+
);
|
|
131
244
|
}
|
|
@@ -5,6 +5,7 @@ import { formatDisplayScope, normalizeStoredSessionKey, parseRouteLike } from '.
|
|
|
5
5
|
import type { BncrRoute } from '../core/types.ts';
|
|
6
6
|
import type { BncrInboundParamsInput } from '../messaging/inbound/contracts.ts';
|
|
7
7
|
import { dispatchBncrInbound } from '../messaging/inbound/dispatch.ts';
|
|
8
|
+
import type { BncrGroupHistoryMap } from '../messaging/inbound/group-history.ts';
|
|
8
9
|
import { parseBncrInboundParams } from '../messaging/inbound/parse.ts';
|
|
9
10
|
import { OUTBOUND_FLUSH_REASON, OUTBOUND_FLUSH_TRIGGER } from '../messaging/outbound/reasons.ts';
|
|
10
11
|
import type { ReplyPayloadInput } from '../messaging/outbound/reply-enqueue.ts';
|
|
@@ -150,6 +151,9 @@ export function createBncrFileInboundHandlersComponent(runtime: {
|
|
|
150
151
|
typeof createBncrFileInboundHandlers
|
|
151
152
|
>[0]['refreshAcceptedFileTransferLiveState'];
|
|
152
153
|
logWarn: Parameters<typeof createBncrFileInboundHandlers>[0]['logWarn'];
|
|
154
|
+
buildCanonicalSessionKey: Parameters<
|
|
155
|
+
typeof createBncrFileInboundHandlers
|
|
156
|
+
>[0]['buildCanonicalSessionKey'];
|
|
153
157
|
fileRecvTransfers: Parameters<typeof createBncrFileInboundHandlers>[0]['fileRecvTransfers'];
|
|
154
158
|
inboundFileTransferMaxBytes: number;
|
|
155
159
|
inboundFileTransferMaxChunks: number;
|
|
@@ -166,6 +170,7 @@ export function createBncrFileInboundHandlersComponent(runtime: {
|
|
|
166
170
|
logWarn: runtime.logWarn,
|
|
167
171
|
parseRouteLike,
|
|
168
172
|
normalizeStoredSessionKey,
|
|
173
|
+
buildCanonicalSessionKey: runtime.buildCanonicalSessionKey,
|
|
169
174
|
saveInboundMediaBuffer: async ({ buffer, mimeType, fileName }) =>
|
|
170
175
|
await saveOpenClawChannelMediaBuffer(
|
|
171
176
|
runtime.getApi(),
|
|
@@ -209,6 +214,10 @@ export function createBncrInboundHandlersComponent(runtime: {
|
|
|
209
214
|
>[0]['buildActiveConnectionDebugList'];
|
|
210
215
|
markLastInboundAt: (accountId: string) => void;
|
|
211
216
|
ensureCanonicalAgentId: Parameters<typeof createBncrInboundHandlers>[0]['ensureCanonicalAgentId'];
|
|
217
|
+
defaultAdminAgentId: Parameters<typeof createBncrInboundHandlers>[0]['defaultAdminAgentId'];
|
|
218
|
+
defaultPublicAgentId: Parameters<typeof createBncrInboundHandlers>[0]['defaultPublicAgentId'];
|
|
219
|
+
sceneRegistry: Parameters<typeof createBncrInboundHandlers>[0]['sceneRegistry'];
|
|
220
|
+
groupHistories: BncrGroupHistoryMap;
|
|
212
221
|
prepareInboundAcceptance: Parameters<
|
|
213
222
|
typeof createBncrInboundHandlers
|
|
214
223
|
>[0]['prepareInboundAcceptance'];
|
|
@@ -250,22 +259,47 @@ export function createBncrInboundHandlersComponent(runtime: {
|
|
|
250
259
|
markLastInboundAt: runtime.markLastInboundAt,
|
|
251
260
|
getConfig: () => getOpenClawRuntimeConfig(runtime.getApi()),
|
|
252
261
|
ensureCanonicalAgentId: runtime.ensureCanonicalAgentId,
|
|
262
|
+
defaultAdminAgentId: runtime.defaultAdminAgentId,
|
|
263
|
+
defaultPublicAgentId: runtime.defaultPublicAgentId,
|
|
264
|
+
sceneRegistry: runtime.sceneRegistry,
|
|
265
|
+
groupHistories: runtime.groupHistories,
|
|
253
266
|
prepareInboundAcceptance: runtime.prepareInboundAcceptance,
|
|
254
267
|
formatDisplayScope,
|
|
255
268
|
logInboundSummary: runtime.logInboundSummary,
|
|
269
|
+
enqueueFromReply: runtime.enqueueFromReply,
|
|
256
270
|
flushOnInboundAccepted: (accountId) =>
|
|
257
271
|
runtime.flushPushQueueBestEffort({
|
|
258
272
|
accountId,
|
|
259
273
|
trigger: OUTBOUND_FLUSH_TRIGGER.INBOUND,
|
|
260
274
|
reason: OUTBOUND_FLUSH_REASON.INBOUND_ACCEPTED,
|
|
261
275
|
}),
|
|
262
|
-
dispatchInbound: ({
|
|
276
|
+
dispatchInbound: ({
|
|
277
|
+
cfg,
|
|
278
|
+
parsed,
|
|
279
|
+
canonicalAgentId,
|
|
280
|
+
resolvedAgentId,
|
|
281
|
+
shouldDispatch,
|
|
282
|
+
shouldAccumulate,
|
|
283
|
+
sceneRegistry,
|
|
284
|
+
groupHistories,
|
|
285
|
+
defaultAdminAgentId,
|
|
286
|
+
defaultPublicAgentId,
|
|
287
|
+
now,
|
|
288
|
+
}) =>
|
|
263
289
|
dispatchBncrInbound({
|
|
264
290
|
api: runtime.getApi(),
|
|
265
291
|
channelId: runtime.channelId,
|
|
266
292
|
cfg,
|
|
267
293
|
parsed,
|
|
268
294
|
canonicalAgentId,
|
|
295
|
+
resolvedAgentId,
|
|
296
|
+
shouldDispatch,
|
|
297
|
+
shouldAccumulate,
|
|
298
|
+
sceneRegistry,
|
|
299
|
+
groupHistories,
|
|
300
|
+
defaultAdminAgentId,
|
|
301
|
+
defaultPublicAgentId,
|
|
302
|
+
now,
|
|
269
303
|
rememberSessionRoute: runtime.rememberSessionRoute,
|
|
270
304
|
enqueueFromReply: runtime.enqueueFromReply,
|
|
271
305
|
setInboundActivity: runtime.setInboundActivity,
|
|
@@ -55,6 +55,7 @@ export function resolveInboundSessionContext(args: {
|
|
|
55
55
|
route: BncrRoute;
|
|
56
56
|
sessionKeyFromRoute?: string;
|
|
57
57
|
canonicalAgentId: string;
|
|
58
|
+
resolvedAgentId?: string;
|
|
58
59
|
taskKey?: string;
|
|
59
60
|
text: string;
|
|
60
61
|
extractedText?: string;
|
|
@@ -74,15 +75,21 @@ export function resolveInboundSessionContext(args: {
|
|
|
74
75
|
peer: args.peer,
|
|
75
76
|
}),
|
|
76
77
|
);
|
|
78
|
+
const normalizedAgentId =
|
|
79
|
+
(args.resolvedAgentId || '').trim() || resolvedRoute.agentId || args.canonicalAgentId;
|
|
77
80
|
const baseSessionKey =
|
|
78
81
|
normalizeInboundSessionKey(
|
|
79
82
|
args.sessionKeyFromRoute || '',
|
|
80
83
|
args.route,
|
|
81
|
-
|
|
84
|
+
normalizedAgentId || '',
|
|
82
85
|
) || resolvedRoute.sessionKey;
|
|
83
86
|
const taskSessionKey = withTaskSessionKey(baseSessionKey, args.taskKey);
|
|
84
87
|
return {
|
|
85
|
-
resolvedRoute
|
|
88
|
+
resolvedRoute: {
|
|
89
|
+
...resolvedRoute,
|
|
90
|
+
agentId: normalizedAgentId || resolvedRoute.agentId,
|
|
91
|
+
sessionKey: baseSessionKey || resolvedRoute.sessionKey,
|
|
92
|
+
},
|
|
86
93
|
baseSessionKey,
|
|
87
94
|
taskSessionKey,
|
|
88
95
|
sessionKey: taskSessionKey || baseSessionKey,
|