@openclaw/msteams 2026.8.1-beta.3 → 2026.8.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/dist/{adapter.runtime-8g-MOPfb.cjs → adapter.runtime-DDuc7sKJ.cjs} +1 -1
- package/dist/api.cjs +2 -2
- package/dist/approval-card-BEblaIto.cjs +303 -0
- package/dist/approval-handler.runtime-C0AWNWXk.cjs +107 -0
- package/dist/{channel-KpWENcgK.cjs → channel-DLn4b6Qi.cjs} +168 -53
- package/dist/channel-config-api.cjs +1 -1
- package/dist/channel-plugin-api.cjs +1 -1
- package/dist/{channel.runtime-Bkzj8jZ0.cjs → channel.runtime-1mH99ZAm.cjs} +49 -608
- package/dist/{channel.setup-mOFtsfYz.cjs → channel.setup-BRbhaigB.cjs} +29 -18
- package/dist/{config-schema-C4CszdDi.cjs → config-schema-MyN2lamA.cjs} +12 -11
- package/dist/configured-state.cjs +20 -0
- package/dist/directory-contract-api.cjs +1 -1
- package/dist/doctor-contract-api.cjs +79 -42
- package/dist/{messenger-IISPSOvj.cjs → messenger-flkiAkkB.cjs} +29 -171
- package/dist/{oauth-C9So7uld.cjs → oauth-Bctn-WPI.cjs} +4 -3
- package/dist/{polls-DvuJvaDG.cjs → polls-P86qBpeV.cjs} +5 -4
- package/dist/qa-runner-api.cjs +1 -1
- package/dist/reaction-types-CL79V_5D.cjs +150 -0
- package/dist/{resolve-allowlist-CIfWUwuc.cjs → resolve-allowlist-BrdWKHE-.cjs} +26 -51
- package/dist/{rolldown-runtime-D6vf50IK.cjs → rolldown-runtime-VH7oDXx4.cjs} +1 -1
- package/dist/runtime-api.cjs +2 -1
- package/dist/secret-input-C65t6kjM.cjs +1 -0
- package/dist/send-C4BjzS1F.cjs +631 -0
- package/dist/setup-plugin-api.cjs +1 -1
- package/dist/{src-C127-DcQ.cjs → src-RSjkJRjI.cjs} +237 -99
- package/dist/{sso-token-store-ChhO1f4i.cjs → sso-token-store-CNbRhz-A.cjs} +1 -1
- package/dist/thread-session-DxOri69r.cjs +63 -0
- package/package.json +13 -11
|
@@ -1,16 +1,20 @@
|
|
|
1
|
-
const require_rolldown_runtime = require("./rolldown-runtime-
|
|
1
|
+
const require_rolldown_runtime = require("./rolldown-runtime-VH7oDXx4.cjs");
|
|
2
2
|
const require_runtime = require("./runtime-gZTAuFux.cjs");
|
|
3
3
|
require("./runtime-api.cjs");
|
|
4
|
-
const require_resolve_allowlist = require("./resolve-allowlist-
|
|
5
|
-
const require_channel = require("./channel-
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
4
|
+
const require_resolve_allowlist = require("./resolve-allowlist-BrdWKHE-.cjs");
|
|
5
|
+
const require_channel = require("./channel-DLn4b6Qi.cjs");
|
|
6
|
+
const require_thread_session = require("./thread-session-DxOri69r.cjs");
|
|
7
|
+
const require_channel_setup = require("./channel.setup-BRbhaigB.cjs");
|
|
8
|
+
const require_polls = require("./polls-P86qBpeV.cjs");
|
|
9
|
+
const require_sso_token_store = require("./sso-token-store-CNbRhz-A.cjs");
|
|
10
|
+
const require_approval_card = require("./approval-card-BEblaIto.cjs");
|
|
11
|
+
const require_messenger = require("./messenger-flkiAkkB.cjs");
|
|
12
|
+
const require_reaction_types = require("./reaction-types-CL79V_5D.cjs");
|
|
10
13
|
let openclaw_plugin_sdk_channel_outbound = require("openclaw/plugin-sdk/channel-outbound");
|
|
11
14
|
let openclaw_plugin_sdk_string_coerce_runtime = require("openclaw/plugin-sdk/string-coerce-runtime");
|
|
12
15
|
let openclaw_plugin_sdk_allow_from = require("openclaw/plugin-sdk/allow-from");
|
|
13
16
|
let openclaw_plugin_sdk_provider_http = require("openclaw/plugin-sdk/provider-http");
|
|
17
|
+
let openclaw_plugin_sdk_account_id = require("openclaw/plugin-sdk/account-id");
|
|
14
18
|
let openclaw_plugin_sdk_media_runtime = require("openclaw/plugin-sdk/media-runtime");
|
|
15
19
|
let openclaw_plugin_sdk_ssrf_runtime = require("openclaw/plugin-sdk/ssrf-runtime");
|
|
16
20
|
let openclaw_plugin_sdk_number_runtime = require("openclaw/plugin-sdk/number-runtime");
|
|
@@ -18,8 +22,10 @@ let openclaw_plugin_sdk_text_utility_runtime = require("openclaw/plugin-sdk/text
|
|
|
18
22
|
let openclaw_plugin_sdk_routing = require("openclaw/plugin-sdk/routing");
|
|
19
23
|
let node_crypto = require("node:crypto");
|
|
20
24
|
node_crypto = require_rolldown_runtime.__toESM(node_crypto, 1);
|
|
25
|
+
let openclaw_plugin_sdk_collection_runtime = require("openclaw/plugin-sdk/collection-runtime");
|
|
21
26
|
let openclaw_plugin_sdk_error_runtime = require("openclaw/plugin-sdk/error-runtime");
|
|
22
27
|
let openclaw_plugin_sdk_channel_inbound = require("openclaw/plugin-sdk/channel-inbound");
|
|
28
|
+
let openclaw_plugin_sdk_approval_gateway_runtime = require("openclaw/plugin-sdk/approval-gateway-runtime");
|
|
23
29
|
let openclaw_plugin_sdk_channel_ingress_runtime = require("openclaw/plugin-sdk/channel-ingress-runtime");
|
|
24
30
|
let openclaw_plugin_sdk_context_visibility_runtime = require("openclaw/plugin-sdk/context-visibility-runtime");
|
|
25
31
|
let openclaw_plugin_sdk_reply_history = require("openclaw/plugin-sdk/reply-history");
|
|
@@ -28,12 +34,11 @@ let openclaw_plugin_sdk_extension_shared = require("openclaw/plugin-sdk/extensio
|
|
|
28
34
|
let openclaw_plugin_sdk_plugin_runtime = require("openclaw/plugin-sdk/plugin-runtime");
|
|
29
35
|
let openclaw_plugin_sdk_dedupe_runtime = require("openclaw/plugin-sdk/dedupe-runtime");
|
|
30
36
|
let openclaw_plugin_sdk_plugin_state_runtime = require("openclaw/plugin-sdk/plugin-state-runtime");
|
|
31
|
-
let openclaw_plugin_sdk_collection_runtime = require("openclaw/plugin-sdk/collection-runtime");
|
|
32
37
|
let openclaw_plugin_sdk_gateway_runtime = require("openclaw/plugin-sdk/gateway-runtime");
|
|
33
38
|
let openclaw_plugin_sdk_channel_pairing = require("openclaw/plugin-sdk/channel-pairing");
|
|
34
|
-
let openclaw_plugin_sdk_account_id = require("openclaw/plugin-sdk/account-id");
|
|
35
39
|
let openclaw_plugin_sdk_runtime_group_policy = require("openclaw/plugin-sdk/runtime-group-policy");
|
|
36
40
|
let openclaw_plugin_sdk_dangerous_name_runtime = require("openclaw/plugin-sdk/dangerous-name-runtime");
|
|
41
|
+
let openclaw_plugin_sdk_account_helpers = require("openclaw/plugin-sdk/account-helpers");
|
|
37
42
|
let openclaw_plugin_sdk_webhook_ingress = require("openclaw/plugin-sdk/webhook-ingress");
|
|
38
43
|
//#region extensions/msteams/src/feedback-reflection-store.ts
|
|
39
44
|
const LEARNINGS_NAMESPACE = "feedback-learnings";
|
|
@@ -166,19 +171,114 @@ function serializeMSTeamsAdaptiveCardActionValue(value) {
|
|
|
166
171
|
}
|
|
167
172
|
}
|
|
168
173
|
//#endregion
|
|
174
|
+
//#region extensions/msteams/src/approval-card-submit.ts
|
|
175
|
+
function isMSTeamsApprovalSubmit(value) {
|
|
176
|
+
if (!(0, openclaw_plugin_sdk_string_coerce_runtime.isRecord)(value)) return false;
|
|
177
|
+
if (value.openclawAction === "approval") return true;
|
|
178
|
+
const data = ((0, openclaw_plugin_sdk_string_coerce_runtime.isRecord)(value.action) ? value.action : void 0)?.data;
|
|
179
|
+
return (0, openclaw_plugin_sdk_string_coerce_runtime.isRecord)(data) && data.openclawAction === "approval";
|
|
180
|
+
}
|
|
181
|
+
async function maybeHandleMSTeamsApprovalCardSubmit(params) {
|
|
182
|
+
const { context, deps } = params;
|
|
183
|
+
if (!isMSTeamsApprovalSubmit(context.activity.value)) return false;
|
|
184
|
+
const ignored = (reason) => deps.log.info("msteams approval ignored", { reason });
|
|
185
|
+
const token = require_approval_card.readMSTeamsApprovalActionToken(context.activity.value);
|
|
186
|
+
if (!token) {
|
|
187
|
+
ignored("missing card token");
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
const binding = require_approval_card.getMSTeamsApprovalCardBinding(token);
|
|
191
|
+
if (!binding) {
|
|
192
|
+
ignored("unknown or expired card token");
|
|
193
|
+
return true;
|
|
194
|
+
}
|
|
195
|
+
if (binding.accountId !== openclaw_plugin_sdk_account_id.DEFAULT_ACCOUNT_ID) {
|
|
196
|
+
ignored("card token account mismatch");
|
|
197
|
+
return true;
|
|
198
|
+
}
|
|
199
|
+
if (require_resolve_allowlist.normalizeMSTeamsConversationId(context.activity.conversation?.id ?? "") !== require_resolve_allowlist.normalizeMSTeamsConversationId(binding.conversationId)) {
|
|
200
|
+
ignored("card token conversation mismatch");
|
|
201
|
+
return true;
|
|
202
|
+
}
|
|
203
|
+
if (context.activity.replyToId && context.activity.replyToId !== binding.activityId) {
|
|
204
|
+
ignored("card token activity mismatch");
|
|
205
|
+
return true;
|
|
206
|
+
}
|
|
207
|
+
if (!binding.allowedDecisions.includes(binding.decision)) {
|
|
208
|
+
ignored("card token decision is no longer allowed");
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
211
|
+
const senderId = context.activity.from?.aadObjectId;
|
|
212
|
+
if (!(require_thread_session.msTeamsApprovalAuth.authorizeActorAction?.({
|
|
213
|
+
cfg: deps.cfg,
|
|
214
|
+
accountId: openclaw_plugin_sdk_account_id.DEFAULT_ACCOUNT_ID,
|
|
215
|
+
senderId,
|
|
216
|
+
action: "approve",
|
|
217
|
+
approvalKind: binding.approvalKind
|
|
218
|
+
}))?.authorized) {
|
|
219
|
+
ignored(`unauthorized actor ${senderId || "unknown"}`);
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
const claim = require_approval_card.claimMSTeamsApprovalCardBinding(token);
|
|
223
|
+
if (claim.kind !== "claimed") {
|
|
224
|
+
ignored(claim.kind === "in-flight" ? "card token resolve already in flight" : "card token already consumed");
|
|
225
|
+
return true;
|
|
226
|
+
}
|
|
227
|
+
const consumed = claim.binding;
|
|
228
|
+
let result;
|
|
229
|
+
try {
|
|
230
|
+
result = await (0, openclaw_plugin_sdk_approval_gateway_runtime.resolveApprovalOverGateway)({
|
|
231
|
+
cfg: deps.cfg,
|
|
232
|
+
approvalId: consumed.approvalId,
|
|
233
|
+
approvalKind: consumed.approvalKind,
|
|
234
|
+
decision: consumed.decision,
|
|
235
|
+
channel: "msteams",
|
|
236
|
+
accountId: openclaw_plugin_sdk_account_id.DEFAULT_ACCOUNT_ID,
|
|
237
|
+
senderId
|
|
238
|
+
});
|
|
239
|
+
await context.updateActivity({
|
|
240
|
+
type: "message",
|
|
241
|
+
id: consumed.activityId,
|
|
242
|
+
attachments: [{
|
|
243
|
+
contentType: "application/vnd.microsoft.card.adaptive",
|
|
244
|
+
content: require_approval_card.buildMSTeamsCanonicalApprovalTerminalCard(result)
|
|
245
|
+
}]
|
|
246
|
+
});
|
|
247
|
+
} catch (error) {
|
|
248
|
+
if ((0, openclaw_plugin_sdk_error_runtime.isApprovalNotFoundError)(error)) {
|
|
249
|
+
require_approval_card.completeMSTeamsApprovalCardBinding(token);
|
|
250
|
+
ignored(`approval expired or no longer exists id=${consumed.approvalId}`);
|
|
251
|
+
return true;
|
|
252
|
+
}
|
|
253
|
+
require_approval_card.releaseMSTeamsApprovalCardBinding(token);
|
|
254
|
+
throw error;
|
|
255
|
+
}
|
|
256
|
+
require_approval_card.completeMSTeamsApprovalCardBinding(token);
|
|
257
|
+
deps.log.info("msteams approval resolved", {
|
|
258
|
+
approvalId: consumed.approvalId,
|
|
259
|
+
approvalKind: consumed.approvalKind,
|
|
260
|
+
applied: result.applied,
|
|
261
|
+
status: result.approval.status,
|
|
262
|
+
senderId
|
|
263
|
+
});
|
|
264
|
+
return true;
|
|
265
|
+
}
|
|
266
|
+
//#endregion
|
|
169
267
|
//#region extensions/msteams/src/monitor-handler/access.ts
|
|
170
268
|
const msteamsIngressIdentity = {
|
|
171
269
|
key: "sender-id",
|
|
270
|
+
authentication: "asserted",
|
|
172
271
|
normalize: normalizeIngressValue,
|
|
173
272
|
aliases: [{
|
|
174
273
|
key: "sender-name",
|
|
175
274
|
kind: "plugin:msteams-sender-name",
|
|
176
275
|
normalizeEntry: normalizeSenderNameIngressValue,
|
|
177
276
|
normalizeSubject: normalizeSenderNameIngressValue,
|
|
178
|
-
|
|
277
|
+
authentication: "mutable"
|
|
179
278
|
}, {
|
|
180
279
|
key: "conversation-id",
|
|
181
280
|
kind: "plugin:msteams-conversation-id",
|
|
281
|
+
authentication: "asserted",
|
|
182
282
|
normalizeEntry: normalizeAllowlistConversationId,
|
|
183
283
|
normalizeSubject: normalizeAllowlistConversationId
|
|
184
284
|
}],
|
|
@@ -221,8 +321,9 @@ async function resolveMSTeamsSenderAccess(params) {
|
|
|
221
321
|
const isDirectMessage = convType === "personal" || !convType && !activity.conversation?.isGroup;
|
|
222
322
|
const senderId = activity.from?.aadObjectId ?? activity.from?.id ?? "unknown";
|
|
223
323
|
const senderName = activity.from?.name ?? activity.from?.id ?? senderId;
|
|
324
|
+
const core = require_runtime.getMSTeamsRuntime();
|
|
224
325
|
const pairing = (0, openclaw_plugin_sdk_channel_pairing.createChannelPairingController)({
|
|
225
|
-
core
|
|
326
|
+
core,
|
|
226
327
|
channel: "msteams",
|
|
227
328
|
accountId: openclaw_plugin_sdk_account_id.DEFAULT_ACCOUNT_ID
|
|
228
329
|
});
|
|
@@ -243,7 +344,23 @@ async function resolveMSTeamsSenderAccess(params) {
|
|
|
243
344
|
const resolved = await (0, openclaw_plugin_sdk_channel_ingress_runtime.resolveStableChannelMessageIngress)({
|
|
244
345
|
channelId: "msteams",
|
|
245
346
|
accountId: pairing.accountId,
|
|
246
|
-
identity:
|
|
347
|
+
identity: {
|
|
348
|
+
...msteamsIngressIdentity,
|
|
349
|
+
resolveParticipant: () => {
|
|
350
|
+
const tenantId = activity.channelData?.tenant?.id ?? activity.conversation?.tenantId;
|
|
351
|
+
const aadId = activity.from?.aadObjectId;
|
|
352
|
+
if (tenantId && aadId) return {
|
|
353
|
+
domain: `entra:${tenantId.toLowerCase()}`,
|
|
354
|
+
idKind: "object-id",
|
|
355
|
+
id: aadId.toLowerCase()
|
|
356
|
+
};
|
|
357
|
+
return msteamsCfg?.appId && activity.from?.id ? {
|
|
358
|
+
domain: `bot:${msteamsCfg.appId.toLowerCase()}`,
|
|
359
|
+
idKind: "channel-account-id",
|
|
360
|
+
id: activity.from.id
|
|
361
|
+
} : void 0;
|
|
362
|
+
}
|
|
363
|
+
},
|
|
247
364
|
cfg: params.cfg,
|
|
248
365
|
readStoreAllowFrom: pairing.readAllowFromStore,
|
|
249
366
|
subject: {
|
|
@@ -561,7 +678,8 @@ async function downloadMSTeamsBotFrameworkAttachment(params) {
|
|
|
561
678
|
allowHosts: params.allowHosts,
|
|
562
679
|
authAllowHosts: params.authAllowHosts
|
|
563
680
|
});
|
|
564
|
-
|
|
681
|
+
const baseUrl = `${normalizeServiceUrl(params.serviceUrl)}/v3/attachments/${encodeURIComponent(params.attachmentId)}`;
|
|
682
|
+
if (!require_resolve_allowlist.isUrlAllowed(baseUrl, policy.allowHosts)) return;
|
|
565
683
|
let accessToken;
|
|
566
684
|
try {
|
|
567
685
|
accessToken = await require_resolve_allowlist.withMSTeamsRequestDeadline({
|
|
@@ -723,9 +841,11 @@ function summarizeMSTeamsHtmlAttachments(attachments) {
|
|
|
723
841
|
while (match) {
|
|
724
842
|
imgTags += 1;
|
|
725
843
|
const src = match[1]?.trim();
|
|
726
|
-
if (src)
|
|
727
|
-
|
|
728
|
-
|
|
844
|
+
if (src) {
|
|
845
|
+
if (src.startsWith("data:")) dataImages += 1;
|
|
846
|
+
else if (src.startsWith("cid:")) cidImages += 1;
|
|
847
|
+
else srcHosts.add(require_resolve_allowlist.safeHostForUrl(src));
|
|
848
|
+
}
|
|
729
849
|
match = require_resolve_allowlist.IMG_SRC_RE.exec(html);
|
|
730
850
|
}
|
|
731
851
|
require_resolve_allowlist.ATTACHMENT_TAG_RE.lastIndex = 0;
|
|
@@ -885,10 +1005,11 @@ function scopeCandidatesForUrl(url) {
|
|
|
885
1005
|
}
|
|
886
1006
|
}
|
|
887
1007
|
async function resolveInlineDataImageMime(inline) {
|
|
888
|
-
const
|
|
1008
|
+
const detectedMime = await require_runtime.getMSTeamsRuntime().media.detectMime({
|
|
889
1009
|
buffer: inline.data,
|
|
890
1010
|
headerMime: inline.contentType
|
|
891
|
-
})
|
|
1011
|
+
});
|
|
1012
|
+
const mime = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeOptionalLowercaseString)(detectedMime ?? inline.contentType);
|
|
892
1013
|
return mime?.startsWith("image/") ? mime : void 0;
|
|
893
1014
|
}
|
|
894
1015
|
async function fetchWithAuthFallback(params) {
|
|
@@ -1479,26 +1600,28 @@ async function resolveMSTeamsInboundMedia(params) {
|
|
|
1479
1600
|
});
|
|
1480
1601
|
const shouldFetchGraphMessage = hasHtmlFileAttachment || hasChannelOrGroupHtml;
|
|
1481
1602
|
const isBotFrameworkPersonalChat = isBotFrameworkPersonalChatId(conversationId);
|
|
1482
|
-
if (hasHtmlFileAttachment && isBotFrameworkPersonalChat)
|
|
1483
|
-
|
|
1484
|
-
conversationId
|
|
1485
|
-
});
|
|
1486
|
-
else {
|
|
1487
|
-
const bfMedia = await downloadMSTeamsBotFrameworkAttachments({
|
|
1488
|
-
serviceUrl,
|
|
1489
|
-
attachmentIds,
|
|
1490
|
-
tokenProvider,
|
|
1491
|
-
maxBytes,
|
|
1492
|
-
allowHosts,
|
|
1493
|
-
authAllowHosts: params.authAllowHosts,
|
|
1494
|
-
preserveFilenames,
|
|
1495
|
-
deadline: params.deadline
|
|
1496
|
-
});
|
|
1497
|
-
if (bfMedia.media.length > 0) mediaList = mergeMSTeamsMediaFacts(mediaList, bfMedia.media, { positionallyAligned: false });
|
|
1498
|
-
if (!hasMaterializedMedia(bfMedia.media)) log.debug?.("bot framework attachments fetch empty", {
|
|
1603
|
+
if (hasHtmlFileAttachment && isBotFrameworkPersonalChat) {
|
|
1604
|
+
if (!serviceUrl) log.debug?.("bot framework attachment skipped (missing serviceUrl)", {
|
|
1499
1605
|
conversationType,
|
|
1500
|
-
|
|
1606
|
+
conversationId
|
|
1501
1607
|
});
|
|
1608
|
+
else {
|
|
1609
|
+
const bfMedia = await downloadMSTeamsBotFrameworkAttachments({
|
|
1610
|
+
serviceUrl,
|
|
1611
|
+
attachmentIds,
|
|
1612
|
+
tokenProvider,
|
|
1613
|
+
maxBytes,
|
|
1614
|
+
allowHosts,
|
|
1615
|
+
authAllowHosts: params.authAllowHosts,
|
|
1616
|
+
preserveFilenames,
|
|
1617
|
+
deadline: params.deadline
|
|
1618
|
+
});
|
|
1619
|
+
if (bfMedia.media.length > 0) mediaList = mergeMSTeamsMediaFacts(mediaList, bfMedia.media, { positionallyAligned: false });
|
|
1620
|
+
if (!hasMaterializedMedia(bfMedia.media)) log.debug?.("bot framework attachments fetch empty", {
|
|
1621
|
+
conversationType,
|
|
1622
|
+
attachmentCount: bfMedia.attachmentCount ?? attachmentIds.length
|
|
1623
|
+
});
|
|
1624
|
+
}
|
|
1502
1625
|
}
|
|
1503
1626
|
if (shouldFetchGraphMessage && !hasMaterializedMedia(mediaList) && !isBotFrameworkPersonalChat) {
|
|
1504
1627
|
const graphTeamAadGroupId = conversationType.trim().toLowerCase() === "channel" && !teamAadGroupId ? await params.resolveTeamAadGroupId?.() : teamAadGroupId;
|
|
@@ -2043,7 +2166,7 @@ function createMSTeamsReplyDispatcher(params) {
|
|
|
2043
2166
|
* chains described in #59731 (60s+ total runs are common). Give tool
|
|
2044
2167
|
* chains up to 10 minutes before auto-stopping the keepalive.
|
|
2045
2168
|
*/
|
|
2046
|
-
const TYPING_KEEPALIVE_MAX_DURATION_MS =
|
|
2169
|
+
const TYPING_KEEPALIVE_MAX_DURATION_MS = 6e5;
|
|
2047
2170
|
const streamActiveRef = { current: () => false };
|
|
2048
2171
|
const streamCanceledRef = { current: () => false };
|
|
2049
2172
|
const rawSendTypingIndicator = async () => {
|
|
@@ -2089,7 +2212,7 @@ function createMSTeamsReplyDispatcher(params) {
|
|
|
2089
2212
|
cfg: params.cfg,
|
|
2090
2213
|
channel: "msteams"
|
|
2091
2214
|
});
|
|
2092
|
-
const mediaMaxBytes = (0,
|
|
2215
|
+
const mediaMaxBytes = (0, openclaw_plugin_sdk_account_helpers.resolveChannelMediaMaxBytes)({
|
|
2093
2216
|
cfg: params.cfg,
|
|
2094
2217
|
resolveChannelLimitMb: ({ cfg }) => cfg.channels?.msteams?.mediaMaxMb
|
|
2095
2218
|
});
|
|
@@ -2437,7 +2560,7 @@ function createMSTeamsReplyDispatcher(params) {
|
|
|
2437
2560
|
//#region extensions/msteams/src/sent-message-cache.ts
|
|
2438
2561
|
const sentMessages = (0, openclaw_plugin_sdk_dedupe_runtime.createPersistentDedupeCache)({
|
|
2439
2562
|
globalKey: Symbol.for("openclaw.msteamsSentMessages"),
|
|
2440
|
-
ttlMs:
|
|
2563
|
+
ttlMs: 864e5,
|
|
2441
2564
|
maxSize: 2e4,
|
|
2442
2565
|
persistent: {
|
|
2443
2566
|
namespace: "msteams.sent-messages",
|
|
@@ -2816,7 +2939,7 @@ async function resolveTeamGroupId(params) {
|
|
|
2816
2939
|
}
|
|
2817
2940
|
//#endregion
|
|
2818
2941
|
//#region extensions/msteams/src/thread-parent-context.ts
|
|
2819
|
-
const PARENT_CACHE_TTL_MS =
|
|
2942
|
+
const PARENT_CACHE_TTL_MS = 3e5;
|
|
2820
2943
|
const PARENT_CACHE_MAX = 100;
|
|
2821
2944
|
const parentCache = /* @__PURE__ */ new Map();
|
|
2822
2945
|
const INJECTED_MAX = 200;
|
|
@@ -2842,7 +2965,7 @@ function resolveParentCacheExpiresAt(nowRaw) {
|
|
|
2842
2965
|
* Uses the injected `fetchParent` (defaults to `fetchChannelMessage`) so
|
|
2843
2966
|
* tests can swap in a stub without mocking the Graph transport.
|
|
2844
2967
|
*/
|
|
2845
|
-
async function fetchParentMessageCached(token, groupId, channelId, parentId, fetchParent =
|
|
2968
|
+
async function fetchParentMessageCached(token, groupId, channelId, parentId, fetchParent = require_reaction_types.fetchChannelMessage) {
|
|
2846
2969
|
const key = buildParentCacheKey(groupId, channelId, parentId);
|
|
2847
2970
|
const now = (0, openclaw_plugin_sdk_number_runtime.asDateTimestampMs)(Date.now());
|
|
2848
2971
|
const cached = parentCache.get(key);
|
|
@@ -2872,11 +2995,11 @@ function summarizeParentMessage(message) {
|
|
|
2872
2995
|
const sender = message.from?.user?.displayName ?? message.from?.application?.displayName ?? "unknown";
|
|
2873
2996
|
const contentType = message.body?.contentType ?? "text";
|
|
2874
2997
|
const raw = message.body?.content ?? "";
|
|
2875
|
-
const text = contentType === "html" ?
|
|
2998
|
+
const text = contentType === "html" ? require_reaction_types.stripHtmlFromTeamsMessage(raw) : raw.replace(/\s+/g, " ").trim();
|
|
2876
2999
|
if (!text) return;
|
|
2877
3000
|
return {
|
|
2878
3001
|
sender,
|
|
2879
|
-
text: text.length > PARENT_TEXT_MAX_CHARS ? `${(0, openclaw_plugin_sdk_text_utility_runtime.truncateUtf16Safe)(text,
|
|
3002
|
+
text: text.length > PARENT_TEXT_MAX_CHARS ? `${(0, openclaw_plugin_sdk_text_utility_runtime.truncateUtf16Safe)(text, 399)}…` : text
|
|
2880
3003
|
};
|
|
2881
3004
|
}
|
|
2882
3005
|
/**
|
|
@@ -2916,7 +3039,7 @@ function prepareMSTeamsThreadRouting(params) {
|
|
|
2916
3039
|
id: params.isDirectMessage ? params.senderId : params.conversationId
|
|
2917
3040
|
}
|
|
2918
3041
|
});
|
|
2919
|
-
route.sessionKey =
|
|
3042
|
+
route.sessionKey = require_thread_session.resolveMSTeamsRouteSessionKey({
|
|
2920
3043
|
baseSessionKey: route.sessionKey,
|
|
2921
3044
|
isChannel: params.isChannel,
|
|
2922
3045
|
conversationMessageId: params.conversationMessageId,
|
|
@@ -2967,7 +3090,7 @@ async function resolveMSTeamsThreadContext(params) {
|
|
|
2967
3090
|
quoteBodyFull = await require_resolve_allowlist.withMSTeamsRequestDeadline({
|
|
2968
3091
|
deadline,
|
|
2969
3092
|
label: "MS Teams quote lookup",
|
|
2970
|
-
work: () =>
|
|
3093
|
+
work: () => require_reaction_types.fetchChatMessageText(graphToken, params.conversationId, quoteMessageId, deadline)
|
|
2971
3094
|
});
|
|
2972
3095
|
} catch (err) {
|
|
2973
3096
|
params.log.debug?.("failed to fetch full quoted message text", { error: require_channel_setup.formatUnknownError(err) });
|
|
@@ -2983,7 +3106,7 @@ async function resolveMSTeamsThreadContext(params) {
|
|
|
2983
3106
|
const [parentResult, repliesResult] = await require_resolve_allowlist.withMSTeamsRequestDeadline({
|
|
2984
3107
|
deadline,
|
|
2985
3108
|
label: "MS Teams thread history",
|
|
2986
|
-
work: () => Promise.allSettled([fetchParentMessageCached(graphToken, teamAadGroupId, params.conversationId, threadParentId, (token, groupId, requestedChannelId, messageId) =>
|
|
3109
|
+
work: () => Promise.allSettled([fetchParentMessageCached(graphToken, teamAadGroupId, params.conversationId, threadParentId, (token, groupId, requestedChannelId, messageId) => require_reaction_types.fetchChannelMessage(token, groupId, requestedChannelId, messageId, deadline)), require_reaction_types.fetchThreadReplies(graphToken, teamAadGroupId, params.conversationId, threadParentId, 50, deadline)])
|
|
2987
3110
|
});
|
|
2988
3111
|
const parentMsg = parentResult.status === "fulfilled" ? parentResult.value : void 0;
|
|
2989
3112
|
const replies = repliesResult.status === "fulfilled" ? repliesResult.value : [];
|
|
@@ -3023,7 +3146,7 @@ async function resolveMSTeamsThreadContext(params) {
|
|
|
3023
3146
|
kind: "thread",
|
|
3024
3147
|
isSenderAllowed: isThreadSenderAllowed
|
|
3025
3148
|
});
|
|
3026
|
-
threadContext =
|
|
3149
|
+
threadContext = require_reaction_types.formatThreadContext(threadMessages, activity.id) || void 0;
|
|
3027
3150
|
} catch (err) {
|
|
3028
3151
|
params.log.debug?.("failed to fetch thread history", { error: require_channel_setup.formatUnknownError(err) });
|
|
3029
3152
|
}
|
|
@@ -3316,7 +3439,8 @@ function createMSTeamsReactionHandler(deps) {
|
|
|
3316
3439
|
log.debug?.("reaction activity missing from.id; skipping");
|
|
3317
3440
|
return;
|
|
3318
3441
|
}
|
|
3319
|
-
const
|
|
3442
|
+
const rawConversationId = activity.conversation?.id ?? "";
|
|
3443
|
+
const conversationId = require_resolve_allowlist.normalizeMSTeamsConversationId(rawConversationId);
|
|
3320
3444
|
const conversationType = activity.conversation?.conversationType ?? "personal";
|
|
3321
3445
|
const isGroupChat = conversationType === "groupChat" || activity.conversation?.isGroup === true;
|
|
3322
3446
|
const isChannel = conversationType === "channel";
|
|
@@ -3349,7 +3473,7 @@ function createMSTeamsReactionHandler(deps) {
|
|
|
3349
3473
|
const targetMessageId = activity.replyToId ?? "unknown";
|
|
3350
3474
|
for (const reaction of reactions) {
|
|
3351
3475
|
const reactionType = reaction.type ?? "unknown";
|
|
3352
|
-
const emoji =
|
|
3476
|
+
const emoji = require_reaction_types.resolveMSTeamsReactionEmoji(reactionType);
|
|
3353
3477
|
const label = direction === "added" ? `Teams reaction ${emoji} added by ${senderName} on message ${targetMessageId}` : `Teams reaction ${emoji} removed by ${senderName} from message ${targetMessageId}`;
|
|
3354
3478
|
log.info(`reaction ${direction}`, {
|
|
3355
3479
|
sender: senderId,
|
|
@@ -3491,6 +3615,10 @@ function registerMSTeamsHandlers(handler, deps) {
|
|
|
3491
3615
|
if (originalRun) handler.run = async (context, turnAdoptionLifecycle) => {
|
|
3492
3616
|
const ctx = context;
|
|
3493
3617
|
if (ctx.activity?.type === "invoke" && ctx.activity?.name === "adaptiveCard/action") {
|
|
3618
|
+
if (await maybeHandleMSTeamsApprovalCardSubmit({
|
|
3619
|
+
context: ctx,
|
|
3620
|
+
deps
|
|
3621
|
+
})) return;
|
|
3494
3622
|
const text = serializeMSTeamsAdaptiveCardActionValue(ctx.activity?.value);
|
|
3495
3623
|
if (text) return await handleTeamsMessage({
|
|
3496
3624
|
...ctx,
|
|
@@ -3511,7 +3639,15 @@ function registerMSTeamsHandlers(handler, deps) {
|
|
|
3511
3639
|
await next();
|
|
3512
3640
|
};
|
|
3513
3641
|
try {
|
|
3514
|
-
const
|
|
3642
|
+
const ctx = context;
|
|
3643
|
+
if (await maybeHandleMSTeamsApprovalCardSubmit({
|
|
3644
|
+
context: ctx,
|
|
3645
|
+
deps
|
|
3646
|
+
})) {
|
|
3647
|
+
await runNext();
|
|
3648
|
+
return;
|
|
3649
|
+
}
|
|
3650
|
+
const result = await handleTeamsMessage(ctx, turnAdoptionLifecycle);
|
|
3515
3651
|
await runNext();
|
|
3516
3652
|
return result;
|
|
3517
3653
|
} catch (err) {
|
|
@@ -3721,60 +3857,61 @@ async function handleMSTeamsFileConsentInvoke(context, log) {
|
|
|
3721
3857
|
return true;
|
|
3722
3858
|
}
|
|
3723
3859
|
}
|
|
3724
|
-
if (consentResponse.action === "accept" && consentResponse.uploadInfo)
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
try {
|
|
3731
|
-
await require_messenger.uploadToConsentUrl({
|
|
3732
|
-
url: consentResponse.uploadInfo.uploadUrl,
|
|
3733
|
-
buffer: pendingFile.buffer,
|
|
3734
|
-
contentType: pendingFile.contentType
|
|
3735
|
-
});
|
|
3736
|
-
const fileInfoCard = require_messenger.buildFileInfoCard({
|
|
3737
|
-
filename: consentResponse.uploadInfo.name,
|
|
3738
|
-
contentUrl: consentResponse.uploadInfo.contentUrl,
|
|
3739
|
-
uniqueId: consentResponse.uploadInfo.uniqueId,
|
|
3740
|
-
fileType: consentResponse.uploadInfo.fileType
|
|
3741
|
-
});
|
|
3742
|
-
if (!pendingFile.consentCardActivityId) await context.sendActivity({
|
|
3743
|
-
type: "message",
|
|
3744
|
-
attachments: [fileInfoCard]
|
|
3860
|
+
if (consentResponse.action === "accept" && consentResponse.uploadInfo) {
|
|
3861
|
+
if (pendingFile) {
|
|
3862
|
+
log.debug?.("user accepted file consent, uploading", {
|
|
3863
|
+
uploadId,
|
|
3864
|
+
filename: pendingFile.filename,
|
|
3865
|
+
size: pendingFile.buffer.length
|
|
3745
3866
|
});
|
|
3746
|
-
|
|
3747
|
-
await
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3867
|
+
try {
|
|
3868
|
+
await require_messenger.uploadToConsentUrl({
|
|
3869
|
+
url: consentResponse.uploadInfo.uploadUrl,
|
|
3870
|
+
buffer: pendingFile.buffer,
|
|
3871
|
+
contentType: pendingFile.contentType
|
|
3872
|
+
});
|
|
3873
|
+
const fileInfoCard = require_messenger.buildFileInfoCard({
|
|
3874
|
+
filename: consentResponse.uploadInfo.name,
|
|
3875
|
+
contentUrl: consentResponse.uploadInfo.contentUrl,
|
|
3876
|
+
uniqueId: consentResponse.uploadInfo.uniqueId,
|
|
3877
|
+
fileType: consentResponse.uploadInfo.fileType
|
|
3751
3878
|
});
|
|
3752
|
-
|
|
3753
|
-
await context.sendActivity({
|
|
3879
|
+
if (!pendingFile.consentCardActivityId) await context.sendActivity({
|
|
3754
3880
|
type: "message",
|
|
3755
3881
|
attachments: [fileInfoCard]
|
|
3756
3882
|
});
|
|
3883
|
+
if (pendingFile.consentCardActivityId) try {
|
|
3884
|
+
await context.updateActivity({
|
|
3885
|
+
id: pendingFile.consentCardActivityId,
|
|
3886
|
+
type: "message",
|
|
3887
|
+
attachments: [fileInfoCard]
|
|
3888
|
+
});
|
|
3889
|
+
} catch {
|
|
3890
|
+
await context.sendActivity({
|
|
3891
|
+
type: "message",
|
|
3892
|
+
attachments: [fileInfoCard]
|
|
3893
|
+
});
|
|
3894
|
+
}
|
|
3895
|
+
log.info("file upload complete", {
|
|
3896
|
+
uploadId,
|
|
3897
|
+
filename: consentResponse.uploadInfo.name,
|
|
3898
|
+
uniqueId: consentResponse.uploadInfo.uniqueId
|
|
3899
|
+
});
|
|
3900
|
+
} catch (err) {
|
|
3901
|
+
log.error("file upload failed", {
|
|
3902
|
+
uploadId,
|
|
3903
|
+
error: require_channel_setup.formatUnknownError(err)
|
|
3904
|
+
});
|
|
3905
|
+
await context.sendActivity("File upload failed. Please try again.");
|
|
3906
|
+
} finally {
|
|
3907
|
+
require_messenger.removePendingUpload(uploadId);
|
|
3908
|
+
await require_messenger.removePendingUploadFs(uploadId);
|
|
3757
3909
|
}
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
uniqueId: consentResponse.uploadInfo.uniqueId
|
|
3762
|
-
});
|
|
3763
|
-
} catch (err) {
|
|
3764
|
-
log.error("file upload failed", {
|
|
3765
|
-
uploadId,
|
|
3766
|
-
error: require_channel_setup.formatUnknownError(err)
|
|
3767
|
-
});
|
|
3768
|
-
await context.sendActivity("File upload failed. Please try again.");
|
|
3769
|
-
} finally {
|
|
3770
|
-
require_messenger.removePendingUpload(uploadId);
|
|
3771
|
-
await require_messenger.removePendingUploadFs(uploadId);
|
|
3910
|
+
} else {
|
|
3911
|
+
log.debug?.("pending file not found for consent", { uploadId });
|
|
3912
|
+
await context.sendActivity(expiredUploadMessage);
|
|
3772
3913
|
}
|
|
3773
3914
|
} else {
|
|
3774
|
-
log.debug?.("pending file not found for consent", { uploadId });
|
|
3775
|
-
await context.sendActivity(expiredUploadMessage);
|
|
3776
|
-
}
|
|
3777
|
-
else {
|
|
3778
3915
|
log.debug?.("user declined file consent", { uploadId });
|
|
3779
3916
|
require_messenger.removePendingUpload(uploadId);
|
|
3780
3917
|
await require_messenger.removePendingUploadFs(uploadId);
|
|
@@ -4069,7 +4206,8 @@ async function monitorMSTeamsProvider(opts) {
|
|
|
4069
4206
|
const unresolved = [];
|
|
4070
4207
|
for (const entry of resolved) if (entry.resolved && entry.id) additions.push(entry.id);
|
|
4071
4208
|
else unresolved.push(entry.input);
|
|
4072
|
-
|
|
4209
|
+
const mapping = resolved.filter((entry) => entry.resolved && entry.id).map((entry) => `${entry.input}→${entry.id}`);
|
|
4210
|
+
(0, openclaw_plugin_sdk_allow_from.summarizeMapping)(label, mapping, unresolved, runtime);
|
|
4073
4211
|
return {
|
|
4074
4212
|
additions,
|
|
4075
4213
|
unresolved
|
|
@@ -4127,10 +4265,10 @@ async function monitorMSTeamsProvider(opts) {
|
|
|
4127
4265
|
};
|
|
4128
4266
|
const port = msteamsCfg.webhook?.port ?? 3978;
|
|
4129
4267
|
const textLimit = core.channel.text.resolveTextChunkLimit(cfg, "msteams");
|
|
4130
|
-
const mediaMaxBytes = (0,
|
|
4268
|
+
const mediaMaxBytes = (0, openclaw_plugin_sdk_account_helpers.resolveChannelMediaMaxBytes)({
|
|
4131
4269
|
cfg,
|
|
4132
4270
|
resolveChannelLimitMb: ({ cfg: channelCfg }) => channelCfg.channels?.msteams?.mediaMaxMb
|
|
4133
|
-
}) ??
|
|
4271
|
+
}) ?? 8388608;
|
|
4134
4272
|
const conversationStore = opts.conversationStore ?? require_polls.createMSTeamsConversationStoreState();
|
|
4135
4273
|
const pollStore = opts.pollStore ?? require_polls.createMSTeamsPollStoreState();
|
|
4136
4274
|
log.info(`starting provider (port ${port})`);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_runtime = require("./runtime-gZTAuFux.cjs");
|
|
2
|
-
const require_polls = require("./polls-
|
|
2
|
+
const require_polls = require("./polls-P86qBpeV.cjs");
|
|
3
3
|
let node_crypto = require("node:crypto");
|
|
4
4
|
//#region extensions/msteams/src/sso-token-store.ts
|
|
5
5
|
/**
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
const require_resolve_allowlist = require("./resolve-allowlist-BrdWKHE-.cjs");
|
|
2
|
+
let openclaw_plugin_sdk_string_coerce_runtime = require("openclaw/plugin-sdk/string-coerce-runtime");
|
|
3
|
+
let openclaw_plugin_sdk_approval_auth_runtime = require("openclaw/plugin-sdk/approval-auth-runtime");
|
|
4
|
+
let openclaw_plugin_sdk_routing = require("openclaw/plugin-sdk/routing");
|
|
5
|
+
//#region extensions/msteams/src/approval-auth.ts
|
|
6
|
+
const MSTEAMS_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
7
|
+
function normalizeMSTeamsApproverId(value) {
|
|
8
|
+
const normalized = require_resolve_allowlist.normalizeMSTeamsMessagingTarget(String(value));
|
|
9
|
+
const id = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeOptionalLowercaseString)(normalized?.startsWith("user:") ? normalized.slice(5) : normalized);
|
|
10
|
+
return id && MSTEAMS_ID_RE.test(id) ? id : void 0;
|
|
11
|
+
}
|
|
12
|
+
function resolveMSTeamsChannelConfig(cfg) {
|
|
13
|
+
return cfg.channels?.msteams;
|
|
14
|
+
}
|
|
15
|
+
const msTeamsApproval = (0, openclaw_plugin_sdk_approval_auth_runtime.createChannelApprovalAuth)({
|
|
16
|
+
channelLabel: "Microsoft Teams",
|
|
17
|
+
resolveInputs: ({ cfg }) => {
|
|
18
|
+
const channel = resolveMSTeamsChannelConfig(cfg);
|
|
19
|
+
return {
|
|
20
|
+
allowFrom: channel?.allowFrom,
|
|
21
|
+
defaultTo: channel?.defaultTo
|
|
22
|
+
};
|
|
23
|
+
},
|
|
24
|
+
normalizeApprover: normalizeMSTeamsApproverId,
|
|
25
|
+
normalizeSenderId: (value) => {
|
|
26
|
+
const trimmed = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeOptionalLowercaseString)(value);
|
|
27
|
+
if (!trimmed) return;
|
|
28
|
+
return MSTEAMS_ID_RE.test(trimmed) ? trimmed : void 0;
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
const getMSTeamsApprovalApprovers = msTeamsApproval.resolveApprovers;
|
|
32
|
+
const msTeamsApprovalAuth = msTeamsApproval.approvalAuth;
|
|
33
|
+
//#endregion
|
|
34
|
+
//#region extensions/msteams/src/monitor-handler/thread-session.ts
|
|
35
|
+
const TRAILING_THREAD_SUFFIX = /(?::thread:[^:]+)+$/;
|
|
36
|
+
function resolveMSTeamsRouteSessionKey(params) {
|
|
37
|
+
const channelThreadId = params.isChannel ? params.conversationMessageId ?? params.replyToId ?? void 0 : void 0;
|
|
38
|
+
const cleanBase = params.baseSessionKey.replace(TRAILING_THREAD_SUFFIX, "");
|
|
39
|
+
return (0, openclaw_plugin_sdk_routing.resolveThreadSessionKeys)({
|
|
40
|
+
baseSessionKey: cleanBase,
|
|
41
|
+
threadId: channelThreadId,
|
|
42
|
+
parentSessionKey: channelThreadId ? cleanBase : void 0
|
|
43
|
+
}).sessionKey;
|
|
44
|
+
}
|
|
45
|
+
//#endregion
|
|
46
|
+
Object.defineProperty(exports, "getMSTeamsApprovalApprovers", {
|
|
47
|
+
enumerable: true,
|
|
48
|
+
get: function() {
|
|
49
|
+
return getMSTeamsApprovalApprovers;
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
Object.defineProperty(exports, "msTeamsApprovalAuth", {
|
|
53
|
+
enumerable: true,
|
|
54
|
+
get: function() {
|
|
55
|
+
return msTeamsApprovalAuth;
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
Object.defineProperty(exports, "resolveMSTeamsRouteSessionKey", {
|
|
59
|
+
enumerable: true,
|
|
60
|
+
get: function() {
|
|
61
|
+
return resolveMSTeamsRouteSessionKey;
|
|
62
|
+
}
|
|
63
|
+
});
|