@openclaw/msteams 2026.8.1-beta.2 → 2026.8.1

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.
@@ -1,25 +1,31 @@
1
1
  const require_rolldown_runtime = require("./rolldown-runtime-D6vf50IK.cjs");
2
2
  const require_runtime = require("./runtime-gZTAuFux.cjs");
3
3
  require("./runtime-api.cjs");
4
- const require_resolve_allowlist = require("./resolve-allowlist-C6YcNC9a.cjs");
5
- const require_channel = require("./channel-DfCbi0d_.cjs");
6
- const require_setup_surface = require("./setup-surface-DAhGL2h8.cjs");
4
+ const require_resolve_allowlist = require("./resolve-allowlist-CWbvAW4v.cjs");
5
+ const require_channel = require("./channel-ChmCvkuA.cjs");
6
+ const require_thread_session = require("./thread-session-Br3R0ovy.cjs");
7
+ const require_channel_setup = require("./channel.setup-CKb8aKCV.cjs");
7
8
  const require_polls = require("./polls-DvuJvaDG.cjs");
8
9
  const require_sso_token_store = require("./sso-token-store-ChhO1f4i.cjs");
9
- const require_messenger = require("./messenger-BqA8G3pY.cjs");
10
+ const require_approval_card = require("./approval-card-B6ZIMO83.cjs");
11
+ const require_messenger = require("./messenger-Ctb9_CO7.cjs");
12
+ const require_reaction_types = require("./reaction-types-DtWOWuDN.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");
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");
13
18
  let openclaw_plugin_sdk_media_runtime = require("openclaw/plugin-sdk/media-runtime");
14
19
  let openclaw_plugin_sdk_ssrf_runtime = require("openclaw/plugin-sdk/ssrf-runtime");
15
- let openclaw_plugin_sdk_provider_http = require("openclaw/plugin-sdk/provider-http");
16
20
  let openclaw_plugin_sdk_number_runtime = require("openclaw/plugin-sdk/number-runtime");
17
21
  let openclaw_plugin_sdk_text_utility_runtime = require("openclaw/plugin-sdk/text-utility-runtime");
18
- let openclaw_plugin_sdk_error_runtime = require("openclaw/plugin-sdk/error-runtime");
19
22
  let openclaw_plugin_sdk_routing = require("openclaw/plugin-sdk/routing");
20
23
  let node_crypto = require("node:crypto");
21
24
  node_crypto = require_rolldown_runtime.__toESM(node_crypto, 1);
25
+ let openclaw_plugin_sdk_collection_runtime = require("openclaw/plugin-sdk/collection-runtime");
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";
@@ -89,11 +94,11 @@ async function runFeedbackReflection(params) {
89
94
  thumbedDownResponse: params.thumbedDownResponse,
90
95
  userComment: params.userComment,
91
96
  cooldownMs,
92
- onRecordError: (err) => log.debug?.("reflection session record failed", { error: require_setup_surface.formatUnknownError(err) }),
93
- onDispatchError: (err) => log.debug?.("reflection reply error", { error: require_setup_surface.formatUnknownError(err) })
97
+ onRecordError: (err) => log.debug?.("reflection session record failed", { error: require_channel_setup.formatUnknownError(err) }),
98
+ onDispatchError: (err) => log.debug?.("reflection reply error", { error: require_channel_setup.formatUnknownError(err) })
94
99
  });
95
100
  } catch (err) {
96
- log.error("reflection dispatch failed", { error: require_setup_surface.formatUnknownError(err) });
101
+ log.error("reflection dispatch failed", { error: require_channel_setup.formatUnknownError(err) });
97
102
  return;
98
103
  }
99
104
  if (reflection.status === "cooldown") {
@@ -116,7 +121,7 @@ async function runFeedbackReflection(params) {
116
121
  learning: reflection.learning
117
122
  });
118
123
  } catch (err) {
119
- log.debug?.("failed to store reflection learning", { error: require_setup_surface.formatUnknownError(err) });
124
+ log.debug?.("failed to store reflection learning", { error: require_channel_setup.formatUnknownError(err) });
120
125
  }
121
126
  const conversationType = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeOptionalLowercaseString)(params.conversationRef.conversation?.conversationType);
122
127
  if (!(conversationType === "personal" && reflection.followUp && Boolean(reflection.userMessage))) {
@@ -133,7 +138,7 @@ async function runFeedbackReflection(params) {
133
138
  }, { serviceUrlBoundary: require_resolve_allowlist.resolveMSTeamsSdkCloudOptions(cfg.channels?.msteams) });
134
139
  log.info("sent reflection follow-up", { sessionKey });
135
140
  } catch (err) {
136
- log.debug?.("failed to send reflection follow-up", { error: require_setup_surface.formatUnknownError(err) });
141
+ log.debug?.("failed to send reflection follow-up", { error: require_channel_setup.formatUnknownError(err) });
137
142
  }
138
143
  }
139
144
  //#endregion
@@ -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
  }],
@@ -243,7 +343,23 @@ async function resolveMSTeamsSenderAccess(params) {
243
343
  const resolved = await (0, openclaw_plugin_sdk_channel_ingress_runtime.resolveStableChannelMessageIngress)({
244
344
  channelId: "msteams",
245
345
  accountId: pairing.accountId,
246
- identity: msteamsIngressIdentity,
346
+ identity: {
347
+ ...msteamsIngressIdentity,
348
+ resolveParticipant: () => {
349
+ const tenantId = activity.channelData?.tenant?.id ?? activity.conversation?.tenantId;
350
+ const aadId = activity.from?.aadObjectId;
351
+ if (tenantId && aadId) return {
352
+ domain: `entra:${tenantId.toLowerCase()}`,
353
+ idKind: "object-id",
354
+ id: aadId.toLowerCase()
355
+ };
356
+ return msteamsCfg?.appId && activity.from?.id ? {
357
+ domain: `bot:${msteamsCfg.appId.toLowerCase()}`,
358
+ idKind: "channel-account-id",
359
+ id: activity.from.id
360
+ } : void 0;
361
+ }
362
+ },
247
363
  cfg: params.cfg,
248
364
  readStoreAllowFrom: pairing.readAllowFromStore,
249
365
  subject: {
@@ -331,7 +447,7 @@ async function admitMSTeamsMessage(params) {
331
447
  });
332
448
  if (senderAccess.decision === "pairing") {
333
449
  params.conversationStore.upsert(params.conversationId, params.conversationRef).catch((err) => {
334
- params.log.debug?.("failed to save conversation reference", { error: require_setup_surface.formatUnknownError(err) });
450
+ params.log.debug?.("failed to save conversation reference", { error: require_channel_setup.formatUnknownError(err) });
335
451
  });
336
452
  if (await pairing.upsertPairingRequest({
337
453
  id: senderId,
@@ -417,7 +533,7 @@ async function admitMSTeamsMessage(params) {
417
533
  return null;
418
534
  }
419
535
  params.conversationStore.upsert(params.conversationId, params.conversationRef).catch((err) => {
420
- params.log.debug?.("failed to save conversation reference", { error: require_setup_surface.formatUnknownError(err) });
536
+ params.log.debug?.("failed to save conversation reference", { error: require_channel_setup.formatUnknownError(err) });
421
537
  });
422
538
  return {
423
539
  ...access,
@@ -1593,7 +1709,7 @@ async function prepareMSTeamsInboundContent(params) {
1593
1709
  })
1594
1710
  });
1595
1711
  } catch (err) {
1596
- params.log.debug?.("failed to resolve inbound Teams media", { error: require_setup_surface.formatUnknownError(err) });
1712
+ params.log.debug?.("failed to resolve inbound Teams media", { error: require_channel_setup.formatUnknownError(err) });
1597
1713
  }
1598
1714
  const inboundMedia = mergeMSTeamsMediaFacts(params.advertisedMedia, mediaList);
1599
1715
  const nativeMediaForComparison = [...params.advertisedMedia, ...mediaList.slice(params.advertisedMedia.length).map((media) => ({
@@ -2089,7 +2205,7 @@ function createMSTeamsReplyDispatcher(params) {
2089
2205
  cfg: params.cfg,
2090
2206
  channel: "msteams"
2091
2207
  });
2092
- const mediaMaxBytes = (0, openclaw_plugin_sdk_media_runtime.resolveChannelMediaMaxBytes)({
2208
+ const mediaMaxBytes = (0, openclaw_plugin_sdk_account_helpers.resolveChannelMediaMaxBytes)({
2093
2209
  cfg: params.cfg,
2094
2210
  resolveChannelLimitMb: ({ cfg }) => cfg.channels?.msteams?.mediaMaxMb
2095
2211
  });
@@ -2135,15 +2251,16 @@ function createMSTeamsReplyDispatcher(params) {
2135
2251
  });
2136
2252
  };
2137
2253
  const queueDeliveryFailureSystemEvent = (failure) => {
2138
- const classification = require_setup_surface.classifyMSTeamsSendError(failure.error);
2139
- const errorText = require_setup_surface.formatUnknownError(failure.error);
2254
+ const classification = require_channel_setup.classifyMSTeamsSendError(failure.error);
2255
+ const errorText = require_channel_setup.formatUnknownError(failure.error);
2140
2256
  const failedAll = failure.failed >= failure.total;
2257
+ const ambiguous = classification.kind === "ambiguous";
2141
2258
  const sentences = [
2142
- `Microsoft Teams delivery failed: ${failedAll ? "the previous reply was not delivered" : `${failure.failed} of ${failure.total} message blocks were not delivered`}.`,
2143
- `The user may not have received ${failedAll ? "that reply" : "the full reply"}.`,
2259
+ `Microsoft Teams delivery failed: ${ambiguous ? failedAll ? "the delivery outcome is unknown for the previous reply" : `the delivery outcome is unknown for ${failure.failed} of ${failure.total} message blocks` : failedAll ? "the previous reply was not delivered" : `${failure.failed} of ${failure.total} message blocks were not delivered`}.`,
2260
+ ambiguous ? void 0 : `The user may not have received ${failedAll ? "that reply" : "the full reply"}.`,
2144
2261
  `Error: ${errorText}.`,
2145
2262
  classification.statusCode != null ? `Status: ${classification.statusCode}.` : void 0,
2146
- classification.kind === "transient" || classification.kind === "throttled" ? "Retrying later may succeed." : void 0
2263
+ require_channel_setup.formatMSTeamsDeliveryFailureGuidance(classification)
2147
2264
  ].filter(Boolean);
2148
2265
  core.system.enqueueSystemEvent(sentences.join(" "), {
2149
2266
  sessionKey: params.sessionKey,
@@ -2236,7 +2353,7 @@ function createMSTeamsReplyDispatcher(params) {
2236
2353
  if (sentIds.length > 0) try {
2237
2354
  params.onSentMessageIds?.(sentIds);
2238
2355
  } catch (error) {
2239
- params.log.warn?.("failed to record sent Teams message ids", { error: require_setup_surface.formatUnknownError(error) });
2356
+ params.log.warn?.("failed to record sent Teams message ids", { error: require_channel_setup.formatUnknownError(error) });
2240
2357
  }
2241
2358
  }
2242
2359
  };
@@ -2268,9 +2385,9 @@ function createMSTeamsReplyDispatcher(params) {
2268
2385
  };
2269
2386
  },
2270
2387
  onError: (err, info) => {
2271
- const errMsg = require_setup_surface.formatUnknownError(err);
2272
- const classification = require_setup_surface.classifyMSTeamsSendError(err);
2273
- const hint = require_setup_surface.formatMSTeamsSendErrorHint(classification);
2388
+ const errMsg = require_channel_setup.formatUnknownError(err);
2389
+ const classification = require_channel_setup.classifyMSTeamsSendError(err);
2390
+ const hint = require_channel_setup.formatMSTeamsSendErrorHint(classification);
2274
2391
  params.runtime.error?.(`msteams ${info.kind} reply failed: ${errMsg}${hint ? ` (${hint})` : ""}`);
2275
2392
  params.log.error("reply failed", {
2276
2393
  kind: info.kind,
@@ -2314,7 +2431,7 @@ function createMSTeamsReplyDispatcher(params) {
2314
2431
  if (nativeResult.messageId) try {
2315
2432
  params.onSentMessageIds?.([nativeResult.messageId]);
2316
2433
  } catch (error) {
2317
- params.log.warn?.("failed to record sent Teams message id", { error: require_setup_surface.formatUnknownError(error) });
2434
+ params.log.warn?.("failed to record sent Teams message id", { error: require_channel_setup.formatUnknownError(error) });
2318
2435
  }
2319
2436
  };
2320
2437
  const previewToolProgressEnabled = (0, openclaw_plugin_sdk_channel_outbound.resolveChannelStreamingPreviewToolProgress)(msteamsCfg, true, teamsStreamMode);
@@ -2643,7 +2760,7 @@ async function dispatchMSTeamsInboundTurn(params) {
2643
2760
  },
2644
2761
  ctxPayload,
2645
2762
  record: { onRecordError: (err) => {
2646
- logVerboseMessage(`msteams: failed updating session meta: ${require_setup_surface.formatUnknownError(err)}`);
2763
+ logVerboseMessage(`msteams: failed updating session meta: ${require_channel_setup.formatUnknownError(err)}`);
2647
2764
  } },
2648
2765
  history: {
2649
2766
  isGroup: isRoomish,
@@ -2662,18 +2779,15 @@ async function dispatchMSTeamsInboundTurn(params) {
2662
2779
  });
2663
2780
  const dispatchResult = turnResult.dispatched ? turnResult.dispatchResult : void 0;
2664
2781
  const counts = (0, openclaw_plugin_sdk_channel_inbound.resolveInboundReplyDispatchCounts)(dispatchResult);
2665
- log.info("dispatch complete", {
2666
- queuedFinal: dispatchResult?.queuedFinal ?? false,
2667
- counts
2668
- });
2782
+ log.info("dispatch complete", { counts });
2669
2783
  if ((0, openclaw_plugin_sdk_channel_inbound.hasFinalInboundReplyDispatch)(dispatchResult)) logVerboseMessage(`msteams: delivered ${counts.final} repl${counts.final === 1 ? "y" : "ies"} to ${teamsTo}`);
2670
2784
  return {
2671
2785
  kind: "completed",
2672
2786
  finalResponses: counts.final
2673
2787
  };
2674
2788
  } catch (err) {
2675
- log.error("dispatch failed", { error: require_setup_surface.formatUnknownError(err) });
2676
- runtime.error(`msteams dispatch failed: ${require_setup_surface.formatUnknownError(err)}`);
2789
+ log.error("dispatch failed", { error: require_channel_setup.formatUnknownError(err) });
2790
+ runtime.error(`msteams dispatch failed: ${require_channel_setup.formatUnknownError(err)}`);
2677
2791
  if (facts.turnAdoptionLifecycle) throw err;
2678
2792
  try {
2679
2793
  await context.sendActivity("⚠️ Something went wrong. Please try again.");
@@ -2844,7 +2958,7 @@ function resolveParentCacheExpiresAt(nowRaw) {
2844
2958
  * Uses the injected `fetchParent` (defaults to `fetchChannelMessage`) so
2845
2959
  * tests can swap in a stub without mocking the Graph transport.
2846
2960
  */
2847
- async function fetchParentMessageCached(token, groupId, channelId, parentId, fetchParent = require_messenger.fetchChannelMessage) {
2961
+ async function fetchParentMessageCached(token, groupId, channelId, parentId, fetchParent = require_reaction_types.fetchChannelMessage) {
2848
2962
  const key = buildParentCacheKey(groupId, channelId, parentId);
2849
2963
  const now = (0, openclaw_plugin_sdk_number_runtime.asDateTimestampMs)(Date.now());
2850
2964
  const cached = parentCache.get(key);
@@ -2874,7 +2988,7 @@ function summarizeParentMessage(message) {
2874
2988
  const sender = message.from?.user?.displayName ?? message.from?.application?.displayName ?? "unknown";
2875
2989
  const contentType = message.body?.contentType ?? "text";
2876
2990
  const raw = message.body?.content ?? "";
2877
- const text = contentType === "html" ? require_messenger.stripHtmlFromTeamsMessage(raw) : raw.replace(/\s+/g, " ").trim();
2991
+ const text = contentType === "html" ? require_reaction_types.stripHtmlFromTeamsMessage(raw) : raw.replace(/\s+/g, " ").trim();
2878
2992
  if (!text) return;
2879
2993
  return {
2880
2994
  sender,
@@ -2918,7 +3032,7 @@ function prepareMSTeamsThreadRouting(params) {
2918
3032
  id: params.isDirectMessage ? params.senderId : params.conversationId
2919
3033
  }
2920
3034
  });
2921
- route.sessionKey = require_channel.resolveMSTeamsRouteSessionKey({
3035
+ route.sessionKey = require_thread_session.resolveMSTeamsRouteSessionKey({
2922
3036
  baseSessionKey: route.sessionKey,
2923
3037
  isChannel: params.isChannel,
2924
3038
  conversationMessageId: params.conversationMessageId,
@@ -2938,7 +3052,7 @@ function prepareMSTeamsThreadRouting(params) {
2938
3052
  }).catch((err) => {
2939
3053
  params.log.debug?.("failed to resolve Teams AAD group ID", {
2940
3054
  teamId: conversationTeamId,
2941
- error: require_setup_surface.formatUnknownError(err)
3055
+ error: require_channel_setup.formatUnknownError(err)
2942
3056
  });
2943
3057
  });
2944
3058
  teamAadGroupId = await teamGroupIdPromise;
@@ -2969,10 +3083,10 @@ async function resolveMSTeamsThreadContext(params) {
2969
3083
  quoteBodyFull = await require_resolve_allowlist.withMSTeamsRequestDeadline({
2970
3084
  deadline,
2971
3085
  label: "MS Teams quote lookup",
2972
- work: () => require_messenger.fetchChatMessageText(graphToken, params.conversationId, quoteMessageId, deadline)
3086
+ work: () => require_reaction_types.fetchChatMessageText(graphToken, params.conversationId, quoteMessageId, deadline)
2973
3087
  });
2974
3088
  } catch (err) {
2975
- params.log.debug?.("failed to fetch full quoted message text", { error: require_setup_surface.formatUnknownError(err) });
3089
+ params.log.debug?.("failed to fetch full quoted message text", { error: require_channel_setup.formatUnknownError(err) });
2976
3090
  }
2977
3091
  let threadContext;
2978
3092
  const threadParentId = activity.replyToId;
@@ -2985,12 +3099,12 @@ async function resolveMSTeamsThreadContext(params) {
2985
3099
  const [parentResult, repliesResult] = await require_resolve_allowlist.withMSTeamsRequestDeadline({
2986
3100
  deadline,
2987
3101
  label: "MS Teams thread history",
2988
- 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)])
3102
+ 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)])
2989
3103
  });
2990
3104
  const parentMsg = parentResult.status === "fulfilled" ? parentResult.value : void 0;
2991
3105
  const replies = repliesResult.status === "fulfilled" ? repliesResult.value : [];
2992
- if (parentResult.status === "rejected") params.log.debug?.("failed to fetch parent message", { error: require_setup_surface.formatUnknownError(parentResult.reason) });
2993
- if (repliesResult.status === "rejected") params.log.debug?.("failed to fetch thread replies", { error: require_setup_surface.formatUnknownError(repliesResult.reason) });
3106
+ if (parentResult.status === "rejected") params.log.debug?.("failed to fetch parent message", { error: require_channel_setup.formatUnknownError(parentResult.reason) });
3107
+ if (repliesResult.status === "rejected") params.log.debug?.("failed to fetch thread replies", { error: require_channel_setup.formatUnknownError(repliesResult.reason) });
2994
3108
  const isThreadSenderAllowed = (message) => (0, openclaw_plugin_sdk_channel_inbound.resolveInboundSupplementalSenderAllowed)({
2995
3109
  isGroup: params.isChannel,
2996
3110
  groupPolicy: params.groupPolicy,
@@ -3025,9 +3139,9 @@ async function resolveMSTeamsThreadContext(params) {
3025
3139
  kind: "thread",
3026
3140
  isSenderAllowed: isThreadSenderAllowed
3027
3141
  });
3028
- threadContext = require_messenger.formatThreadContext(threadMessages, activity.id) || void 0;
3142
+ threadContext = require_reaction_types.formatThreadContext(threadMessages, activity.id) || void 0;
3029
3143
  } catch (err) {
3030
- params.log.debug?.("failed to fetch thread history", { error: require_setup_surface.formatUnknownError(err) });
3144
+ params.log.debug?.("failed to fetch thread history", { error: require_channel_setup.formatUnknownError(err) });
3031
3145
  }
3032
3146
  quoteSenderName ??= params.quoteInfo?.sender;
3033
3147
  return {
@@ -3106,7 +3220,7 @@ function createMSTeamsMessageHandler(deps) {
3106
3220
  } catch (err) {
3107
3221
  log.error("failed to record poll vote", {
3108
3222
  pollId: pollVote.pollId,
3109
- error: require_setup_surface.formatUnknownError(err)
3223
+ error: require_channel_setup.formatUnknownError(err)
3110
3224
  });
3111
3225
  }
3112
3226
  return;
@@ -3283,7 +3397,7 @@ function createMSTeamsMessageHandler(deps) {
3283
3397
  });
3284
3398
  },
3285
3399
  onError: (err) => {
3286
- runtime.error(`msteams debounce flush failed: ${require_setup_surface.formatUnknownError(err)}`);
3400
+ runtime.error(`msteams debounce flush failed: ${require_channel_setup.formatUnknownError(err)}`);
3287
3401
  }
3288
3402
  });
3289
3403
  return async function handleTeamsMessage(context, turnAdoptionLifecycle) {
@@ -3307,7 +3421,8 @@ function createMSTeamsReactionHandler(deps) {
3307
3421
  const msteamsCfg = cfg.channels?.msteams;
3308
3422
  return async function handleReaction(context, direction) {
3309
3423
  const activity = context.activity;
3310
- const reactions = direction === "added" ? activity.reactionsAdded ?? [] : activity.reactionsRemoved ?? [];
3424
+ const rawReactions = direction === "added" ? activity.reactionsAdded : activity.reactionsRemoved;
3425
+ const reactions = Array.isArray(rawReactions) ? rawReactions : [];
3311
3426
  if (reactions.length === 0) {
3312
3427
  log.debug?.("reaction activity has no reactions; skipping");
3313
3428
  return;
@@ -3350,7 +3465,7 @@ function createMSTeamsReactionHandler(deps) {
3350
3465
  const targetMessageId = activity.replyToId ?? "unknown";
3351
3466
  for (const reaction of reactions) {
3352
3467
  const reactionType = reaction.type ?? "unknown";
3353
- const emoji = require_messenger.resolveMSTeamsReactionEmoji(reactionType);
3468
+ const emoji = require_reaction_types.resolveMSTeamsReactionEmoji(reactionType);
3354
3469
  const label = direction === "added" ? `Teams reaction ${emoji} added by ${senderName} on message ${targetMessageId}` : `Teams reaction ${emoji} removed by ${senderName} from message ${targetMessageId}`;
3355
3470
  log.info(`reaction ${direction}`, {
3356
3471
  sender: senderId,
@@ -3492,6 +3607,10 @@ function registerMSTeamsHandlers(handler, deps) {
3492
3607
  if (originalRun) handler.run = async (context, turnAdoptionLifecycle) => {
3493
3608
  const ctx = context;
3494
3609
  if (ctx.activity?.type === "invoke" && ctx.activity?.name === "adaptiveCard/action") {
3610
+ if (await maybeHandleMSTeamsApprovalCardSubmit({
3611
+ context: ctx,
3612
+ deps
3613
+ })) return;
3495
3614
  const text = serializeMSTeamsAdaptiveCardActionValue(ctx.activity?.value);
3496
3615
  if (text) return await handleTeamsMessage({
3497
3616
  ...ctx,
@@ -3512,12 +3631,20 @@ function registerMSTeamsHandlers(handler, deps) {
3512
3631
  await next();
3513
3632
  };
3514
3633
  try {
3515
- const result = await handleTeamsMessage(context, turnAdoptionLifecycle);
3634
+ const ctx = context;
3635
+ if (await maybeHandleMSTeamsApprovalCardSubmit({
3636
+ context: ctx,
3637
+ deps
3638
+ })) {
3639
+ await runNext();
3640
+ return;
3641
+ }
3642
+ const result = await handleTeamsMessage(ctx, turnAdoptionLifecycle);
3516
3643
  await runNext();
3517
3644
  return result;
3518
3645
  } catch (err) {
3519
3646
  if (turnAdoptionLifecycle) throw err;
3520
- deps.runtime.error(`msteams handler failed: ${require_setup_surface.formatUnknownError(err)}`);
3647
+ deps.runtime.error(`msteams handler failed: ${require_channel_setup.formatUnknownError(err)}`);
3521
3648
  }
3522
3649
  if (!nextRan) await runNext();
3523
3650
  });
@@ -3543,7 +3670,7 @@ function registerMSTeamsHandlers(handler, deps) {
3543
3670
  });
3544
3671
  deps.log.info("sent welcome card");
3545
3672
  } catch (err) {
3546
- deps.log.debug?.("failed to send welcome card", { error: require_setup_surface.formatUnknownError(err) });
3673
+ deps.log.debug?.("failed to send welcome card", { error: require_channel_setup.formatUnknownError(err) });
3547
3674
  }
3548
3675
  } else if (!isPersonal && msteamsCfg?.groupWelcomeCard === true) {
3549
3676
  const botName = ctx.activity?.recipient?.name ?? void 0;
@@ -3551,7 +3678,7 @@ function registerMSTeamsHandlers(handler, deps) {
3551
3678
  await ctx.sendActivity(buildGroupWelcomeText(botName));
3552
3679
  deps.log.info("sent group welcome message");
3553
3680
  } catch (err) {
3554
- deps.log.debug?.("failed to send group welcome", { error: require_setup_surface.formatUnknownError(err) });
3681
+ deps.log.debug?.("failed to send group welcome", { error: require_channel_setup.formatUnknownError(err) });
3555
3682
  }
3556
3683
  } else deps.log.debug?.("skipping welcome (disabled by config or conversation type)");
3557
3684
  } else deps.log.debug?.("member added", { member: member.id });
@@ -3687,7 +3814,7 @@ async function runMSTeamsFeedbackInvokeHandler(context, deps) {
3687
3814
  userComment,
3688
3815
  log: deps.log
3689
3816
  }).catch((err) => {
3690
- deps.log.error("feedback reflection failed", { error: require_setup_surface.formatUnknownError(err) });
3817
+ deps.log.error("feedback reflection failed", { error: require_channel_setup.formatUnknownError(err) });
3691
3818
  });
3692
3819
  return true;
3693
3820
  }
@@ -3764,7 +3891,7 @@ async function handleMSTeamsFileConsentInvoke(context, log) {
3764
3891
  } catch (err) {
3765
3892
  log.error("file upload failed", {
3766
3893
  uploadId,
3767
- error: require_setup_surface.formatUnknownError(err)
3894
+ error: require_channel_setup.formatUnknownError(err)
3768
3895
  });
3769
3896
  await context.sendActivity("File upload failed. Please try again.");
3770
3897
  } finally {
@@ -3797,7 +3924,7 @@ async function runMSTeamsFileConsentInvokeHandler(context, log) {
3797
3924
  }
3798
3925
  });
3799
3926
  } catch (err) {
3800
- log.debug?.("file consent handler error", { error: require_setup_surface.formatUnknownError(err) });
3927
+ log.debug?.("file consent handler error", { error: require_channel_setup.formatUnknownError(err) });
3801
3928
  }
3802
3929
  }
3803
3930
  //#endregion
@@ -3902,7 +4029,7 @@ function createMSTeamsIngress(options) {
3902
4029
  reason: error.reason,
3903
4030
  message: error.message
3904
4031
  };
3905
- return require_setup_surface.classifyMSTeamsSendError(error).kind === "auth" ? {
4032
+ return require_channel_setup.classifyMSTeamsSendError(error).kind === "auth" ? {
3906
4033
  reason: "authentication-failed",
3907
4034
  message: (0, openclaw_plugin_sdk_error_runtime.formatErrorMessage)(error)
3908
4035
  } : null;
@@ -3955,6 +4082,54 @@ function createMSTeamsIngress(options) {
3955
4082
  };
3956
4083
  }
3957
4084
  //#endregion
4085
+ //#region extensions/msteams/src/replay-context.ts
4086
+ function createMSTeamsReplayContext(activity, app, serviceUrlBoundary) {
4087
+ const rawConversationId = activity.conversation?.id ?? "";
4088
+ const conversationId = require_resolve_allowlist.normalizeMSTeamsConversationId(rawConversationId);
4089
+ const conversationType = activity.conversation?.conversationType ?? "personal";
4090
+ const normalizedConversationType = conversationType.toLowerCase();
4091
+ const threadActivityId = normalizedConversationType === "channel" ? require_resolve_allowlist.extractMSTeamsConversationMessageId(rawConversationId) ?? activity.replyToId : void 0;
4092
+ const quoteActivityId = normalizedConversationType === "channel" || normalizedConversationType === "groupchat" ? activity.id : void 0;
4093
+ const tenantId = activity.channelData?.tenant?.id ?? activity.conversation?.tenantId;
4094
+ const reference = {
4095
+ activityId: activity.id,
4096
+ user: activity.from,
4097
+ agent: activity.recipient,
4098
+ conversation: {
4099
+ id: conversationId,
4100
+ conversationType,
4101
+ ...tenantId ? { tenantId } : {}
4102
+ },
4103
+ channelId: activity.channelId,
4104
+ serviceUrl: activity.serviceUrl,
4105
+ locale: activity.locale,
4106
+ ...tenantId ? { tenantId } : {},
4107
+ ...activity.from?.aadObjectId ? { aadObjectId: activity.from.aadObjectId } : {}
4108
+ };
4109
+ const proactiveOptions = {
4110
+ ...quoteActivityId ? { quoteActivityId } : {},
4111
+ ...threadActivityId ? { threadActivityId } : {},
4112
+ serviceUrlBoundary
4113
+ };
4114
+ const sendActivity = (outbound) => require_messenger.sendMSTeamsActivityWithReference(app, reference, outbound, proactiveOptions);
4115
+ return {
4116
+ activity,
4117
+ sendActivity,
4118
+ sendActivities: async (activities) => {
4119
+ const results = [];
4120
+ for (const outbound of activities) results.push(await sendActivity(outbound));
4121
+ return results;
4122
+ },
4123
+ updateActivity: async (outbound) => {
4124
+ return await require_messenger.updateMSTeamsActivityWithReference(app, reference, typeof outbound.id === "string" ? outbound.id : "", outbound, proactiveOptions);
4125
+ },
4126
+ deleteActivity: async (activityId) => {
4127
+ await require_messenger.deleteMSTeamsActivityWithReference(app, reference, activityId, proactiveOptions);
4128
+ },
4129
+ getTeamDetails: (teamId) => app.api.teams.getById(teamId)
4130
+ };
4131
+ }
4132
+ //#endregion
3958
4133
  //#region extensions/msteams/src/webhook-timeouts.ts
3959
4134
  const MSTEAMS_WEBHOOK_INACTIVITY_TIMEOUT_MS = 3e4;
3960
4135
  const MSTEAMS_WEBHOOK_REQUEST_TIMEOUT_MS = 3e4;
@@ -4059,7 +4234,7 @@ async function monitorMSTeamsProvider(opts) {
4059
4234
  (0, openclaw_plugin_sdk_allow_from.summarizeMapping)("msteams channels", resolved.mapping, resolved.unresolved, runtime);
4060
4235
  }
4061
4236
  } catch (err) {
4062
- runtime.error?.(`msteams resolve failed; mutable allowlist entries are disabled. ${require_setup_surface.formatUnknownError(err)}`);
4237
+ runtime.error?.(`msteams resolve failed; mutable allowlist entries are disabled. ${require_channel_setup.formatUnknownError(err)}`);
4063
4238
  }
4064
4239
  if (configuredGroupAllowFrom == null && groupAllowFrom) groupAllowFrom = (0, openclaw_plugin_sdk_allow_from.mergeAllowlist)({
4065
4240
  existing: groupAllowFrom,
@@ -4080,7 +4255,7 @@ async function monitorMSTeamsProvider(opts) {
4080
4255
  };
4081
4256
  const port = msteamsCfg.webhook?.port ?? 3978;
4082
4257
  const textLimit = core.channel.text.resolveTextChunkLimit(cfg, "msteams");
4083
- const mediaMaxBytes = (0, openclaw_plugin_sdk_media_runtime.resolveChannelMediaMaxBytes)({
4258
+ const mediaMaxBytes = (0, openclaw_plugin_sdk_account_helpers.resolveChannelMediaMaxBytes)({
4084
4259
  cfg,
4085
4260
  resolveChannelLimitMb: ({ cfg: channelCfg }) => channelCfg.channels?.msteams?.mediaMaxMb
4086
4261
  }) ?? 8 * 1024 * 1024;
@@ -4213,7 +4388,7 @@ async function monitorMSTeamsProvider(opts) {
4213
4388
  } catch (err) {
4214
4389
  log.error("failed to record poll vote", {
4215
4390
  pollId: vote.pollId,
4216
- error: require_setup_surface.formatUnknownError(err)
4391
+ error: require_channel_setup.formatUnknownError(err)
4217
4392
  });
4218
4393
  return {
4219
4394
  statusCode: 500,
@@ -4236,7 +4411,7 @@ async function monitorMSTeamsProvider(opts) {
4236
4411
  value: "OK"
4237
4412
  };
4238
4413
  } catch (err) {
4239
- log.error("msteams card.action failed", { error: require_setup_surface.formatUnknownError(err) });
4414
+ log.error("msteams card.action failed", { error: require_channel_setup.formatUnknownError(err) });
4240
4415
  return {
4241
4416
  statusCode: 500,
4242
4417
  type: "application/vnd.microsoft.error",
@@ -4304,7 +4479,7 @@ async function monitorMSTeamsProvider(opts) {
4304
4479
  hasExpiry: Boolean(ctx.token.expiration)
4305
4480
  });
4306
4481
  })().catch((err) => {
4307
- log.error("msteams sso token persistence failed", { error: require_setup_surface.formatUnknownError(err) });
4482
+ log.error("msteams sso token persistence failed", { error: require_channel_setup.formatUnknownError(err) });
4308
4483
  });
4309
4484
  });
4310
4485
  app.on("message.submit", async (ctx) => {
@@ -4325,7 +4500,7 @@ async function monitorMSTeamsProvider(opts) {
4325
4500
  try {
4326
4501
  await handler.run(adaptedCtx);
4327
4502
  } catch (err) {
4328
- log.error("msteams non-turn activity failed", { error: require_setup_surface.formatUnknownError(err) });
4503
+ log.error("msteams non-turn activity failed", { error: require_channel_setup.formatUnknownError(err) });
4329
4504
  }
4330
4505
  });
4331
4506
  await app.initialize();
@@ -4335,7 +4510,7 @@ async function monitorMSTeamsProvider(opts) {
4335
4510
  const onListen = (err) => err ? reject(err) : resolve(server);
4336
4511
  const server = privateQaRuntime ? expressApp.listen(port, privateQaRuntime.listenHost, onListen) : expressApp.listen(port, onListen);
4337
4512
  }).catch(async (err) => {
4338
- log.error("msteams server error", { error: require_setup_surface.formatUnknownError(err) });
4513
+ log.error("msteams server error", { error: require_channel_setup.formatUnknownError(err) });
4339
4514
  await ingress.stop();
4340
4515
  throw err;
4341
4516
  });
@@ -4343,14 +4518,14 @@ async function monitorMSTeamsProvider(opts) {
4343
4518
  publishMSTeamsReady(opts.statusSink);
4344
4519
  applyMSTeamsWebhookTimeouts(httpServer);
4345
4520
  httpServer.on("error", (err) => {
4346
- log.error("msteams server error", { error: require_setup_surface.formatUnknownError(err) });
4347
- publishMSTeamsRecovering(opts.statusSink, require_setup_surface.formatUnknownError(err));
4521
+ log.error("msteams server error", { error: require_channel_setup.formatUnknownError(err) });
4522
+ publishMSTeamsRecovering(opts.statusSink, require_channel_setup.formatUnknownError(err));
4348
4523
  });
4349
4524
  const shutdown = async () => {
4350
4525
  log.info("shutting down msteams provider");
4351
4526
  await new Promise((resolve) => {
4352
4527
  httpServer.close((err) => {
4353
- if (err) log.debug?.("msteams server close error", { error: require_setup_surface.formatUnknownError(err) });
4528
+ if (err) log.debug?.("msteams server close error", { error: require_channel_setup.formatUnknownError(err) });
4354
4529
  resolve();
4355
4530
  });
4356
4531
  });
@@ -4411,47 +4586,6 @@ function buildActivityHandler() {
4411
4586
  };
4412
4587
  return handler;
4413
4588
  }
4414
- function createMSTeamsReplayContext(activity, app, serviceUrlBoundary) {
4415
- const rawConversationId = activity.conversation?.id ?? "";
4416
- const conversationId = require_resolve_allowlist.normalizeMSTeamsConversationId(rawConversationId);
4417
- const conversationType = activity.conversation?.conversationType ?? "personal";
4418
- const threadActivityId = conversationType.toLowerCase() === "channel" ? require_resolve_allowlist.extractMSTeamsConversationMessageId(rawConversationId) ?? activity.replyToId : void 0;
4419
- const tenantId = activity.channelData?.tenant?.id ?? activity.conversation?.tenantId;
4420
- const reference = {
4421
- activityId: activity.id,
4422
- user: activity.from,
4423
- agent: activity.recipient,
4424
- conversation: {
4425
- id: conversationId,
4426
- conversationType,
4427
- ...tenantId ? { tenantId } : {}
4428
- },
4429
- channelId: activity.channelId,
4430
- serviceUrl: activity.serviceUrl,
4431
- locale: activity.locale,
4432
- ...tenantId ? { tenantId } : {},
4433
- ...activity.from?.aadObjectId ? { aadObjectId: activity.from.aadObjectId } : {}
4434
- };
4435
- const proactiveOptions = {
4436
- ...threadActivityId ? { threadActivityId } : {},
4437
- serviceUrlBoundary
4438
- };
4439
- const sendActivity = (outbound) => require_messenger.sendMSTeamsActivityWithReference(app, reference, outbound, proactiveOptions);
4440
- return {
4441
- activity,
4442
- sendActivity,
4443
- sendActivities: async (activities) => {
4444
- const results = [];
4445
- for (const outbound of activities) results.push(await sendActivity(outbound));
4446
- return results;
4447
- },
4448
- updateActivity: async (outbound) => await require_messenger.updateMSTeamsActivityWithReference(app, reference, typeof outbound.id === "string" ? outbound.id : "", outbound, proactiveOptions),
4449
- deleteActivity: async (activityId) => {
4450
- await require_messenger.deleteMSTeamsActivityWithReference(app, reference, activityId, proactiveOptions);
4451
- },
4452
- getTeamDetails: (teamId) => app.api.teams.getById(teamId)
4453
- };
4454
- }
4455
4589
  /**
4456
4590
  * Adapt a new @microsoft/teams.apps SDK context to the MSTeamsTurnContext interface
4457
4591
  * our handlers expect. The new SDK uses reply()/send() instead of sendActivity().