@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.
Files changed (28) hide show
  1. package/dist/{adapter.runtime-8g-MOPfb.cjs → adapter.runtime-DDuc7sKJ.cjs} +1 -1
  2. package/dist/api.cjs +2 -2
  3. package/dist/approval-card-BEblaIto.cjs +303 -0
  4. package/dist/approval-handler.runtime-C0AWNWXk.cjs +107 -0
  5. package/dist/{channel-KpWENcgK.cjs → channel-DLn4b6Qi.cjs} +168 -53
  6. package/dist/channel-config-api.cjs +1 -1
  7. package/dist/channel-plugin-api.cjs +1 -1
  8. package/dist/{channel.runtime-Bkzj8jZ0.cjs → channel.runtime-1mH99ZAm.cjs} +49 -608
  9. package/dist/{channel.setup-mOFtsfYz.cjs → channel.setup-BRbhaigB.cjs} +29 -18
  10. package/dist/{config-schema-C4CszdDi.cjs → config-schema-MyN2lamA.cjs} +12 -11
  11. package/dist/configured-state.cjs +20 -0
  12. package/dist/directory-contract-api.cjs +1 -1
  13. package/dist/doctor-contract-api.cjs +79 -42
  14. package/dist/{messenger-IISPSOvj.cjs → messenger-flkiAkkB.cjs} +29 -171
  15. package/dist/{oauth-C9So7uld.cjs → oauth-Bctn-WPI.cjs} +4 -3
  16. package/dist/{polls-DvuJvaDG.cjs → polls-P86qBpeV.cjs} +5 -4
  17. package/dist/qa-runner-api.cjs +1 -1
  18. package/dist/reaction-types-CL79V_5D.cjs +150 -0
  19. package/dist/{resolve-allowlist-CIfWUwuc.cjs → resolve-allowlist-BrdWKHE-.cjs} +26 -51
  20. package/dist/{rolldown-runtime-D6vf50IK.cjs → rolldown-runtime-VH7oDXx4.cjs} +1 -1
  21. package/dist/runtime-api.cjs +2 -1
  22. package/dist/secret-input-C65t6kjM.cjs +1 -0
  23. package/dist/send-C4BjzS1F.cjs +631 -0
  24. package/dist/setup-plugin-api.cjs +1 -1
  25. package/dist/{src-C127-DcQ.cjs → src-RSjkJRjI.cjs} +237 -99
  26. package/dist/{sso-token-store-ChhO1f4i.cjs → sso-token-store-CNbRhz-A.cjs} +1 -1
  27. package/dist/thread-session-DxOri69r.cjs +63 -0
  28. package/package.json +13 -11
@@ -1,16 +1,20 @@
1
- const require_rolldown_runtime = require("./rolldown-runtime-D6vf50IK.cjs");
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-CIfWUwuc.cjs");
5
- const require_channel = require("./channel-KpWENcgK.cjs");
6
- const require_channel_setup = require("./channel.setup-mOFtsfYz.cjs");
7
- const require_polls = require("./polls-DvuJvaDG.cjs");
8
- const require_sso_token_store = require("./sso-token-store-ChhO1f4i.cjs");
9
- const require_messenger = require("./messenger-IISPSOvj.cjs");
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
- dangerous: true
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: require_runtime.getMSTeamsRuntime(),
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: msteamsIngressIdentity,
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
- if (!require_resolve_allowlist.isUrlAllowed(`${normalizeServiceUrl(params.serviceUrl)}/v3/attachments/${encodeURIComponent(params.attachmentId)}`, policy.allowHosts)) return;
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) if (src.startsWith("data:")) dataImages += 1;
727
- else if (src.startsWith("cid:")) cidImages += 1;
728
- else srcHosts.add(require_resolve_allowlist.safeHostForUrl(src));
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 mime = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeOptionalLowercaseString)(await require_runtime.getMSTeamsRuntime().media.detectMime({
1008
+ const detectedMime = await require_runtime.getMSTeamsRuntime().media.detectMime({
889
1009
  buffer: inline.data,
890
1010
  headerMime: inline.contentType
891
- }) ?? inline.contentType);
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) if (!serviceUrl) log.debug?.("bot framework attachment skipped (missing serviceUrl)", {
1483
- conversationType,
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
- attachmentCount: bfMedia.attachmentCount ?? attachmentIds.length
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 = 10 * 6e4;
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, openclaw_plugin_sdk_media_runtime.resolveChannelMediaMaxBytes)({
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: 1440 * 60 * 1e3,
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 = 300 * 1e3;
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 = require_messenger.fetchChannelMessage) {
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" ? require_messenger.stripHtmlFromTeamsMessage(raw) : raw.replace(/\s+/g, " ").trim();
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, PARENT_TEXT_MAX_CHARS - 1)}…` : 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 = require_channel.resolveMSTeamsRouteSessionKey({
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: () => require_messenger.fetchChatMessageText(graphToken, params.conversationId, quoteMessageId, deadline)
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) => require_messenger.fetchChannelMessage(token, groupId, requestedChannelId, messageId, deadline)), require_messenger.fetchThreadReplies(graphToken, teamAadGroupId, params.conversationId, threadParentId, 50, deadline)])
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 = require_messenger.formatThreadContext(threadMessages, activity.id) || void 0;
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 conversationId = require_resolve_allowlist.normalizeMSTeamsConversationId(activity.conversation?.id ?? "");
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 = require_messenger.resolveMSTeamsReactionEmoji(reactionType);
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 result = await handleTeamsMessage(context, turnAdoptionLifecycle);
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) if (pendingFile) {
3725
- log.debug?.("user accepted file consent, uploading", {
3726
- uploadId,
3727
- filename: pendingFile.filename,
3728
- size: pendingFile.buffer.length
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
- if (pendingFile.consentCardActivityId) try {
3747
- await context.updateActivity({
3748
- id: pendingFile.consentCardActivityId,
3749
- type: "message",
3750
- attachments: [fileInfoCard]
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
- } catch {
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
- log.info("file upload complete", {
3759
- uploadId,
3760
- filename: consentResponse.uploadInfo.name,
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
- (0, openclaw_plugin_sdk_allow_from.summarizeMapping)(label, resolved.filter((entry) => entry.resolved && entry.id).map((entry) => `${entry.input}→${entry.id}`), unresolved, runtime);
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, openclaw_plugin_sdk_media_runtime.resolveChannelMediaMaxBytes)({
4268
+ const mediaMaxBytes = (0, openclaw_plugin_sdk_account_helpers.resolveChannelMediaMaxBytes)({
4131
4269
  cfg,
4132
4270
  resolveChannelLimitMb: ({ cfg: channelCfg }) => channelCfg.channels?.msteams?.mediaMaxMb
4133
- }) ?? 8 * 1024 * 1024;
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-DvuJvaDG.cjs");
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
+ });