@openclaw/msteams 2026.8.1-beta.2 → 2026.9.1-beta.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-B6FQAa3r.cjs");
5
+ const require_channel = require("./channel-BsqcQ0E9.cjs");
6
+ const require_thread_session = require("./thread-session-DdWfgc8U.cjs");
7
+ const require_channel_setup = require("./channel.setup-BvYxZIFG.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-BJB30CC2.cjs");
12
+ const require_reaction_types = require("./reaction-types-dGkp4bkW.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,10 +34,8 @@ 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");
37
41
  let openclaw_plugin_sdk_webhook_ingress = require("openclaw/plugin-sdk/webhook-ingress");
@@ -89,11 +93,11 @@ async function runFeedbackReflection(params) {
89
93
  thumbedDownResponse: params.thumbedDownResponse,
90
94
  userComment: params.userComment,
91
95
  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) })
96
+ onRecordError: (err) => log.debug?.("reflection session record failed", { error: require_channel_setup.formatUnknownError(err) }),
97
+ onDispatchError: (err) => log.debug?.("reflection reply error", { error: require_channel_setup.formatUnknownError(err) })
94
98
  });
95
99
  } catch (err) {
96
- log.error("reflection dispatch failed", { error: require_setup_surface.formatUnknownError(err) });
100
+ log.error("reflection dispatch failed", { error: require_channel_setup.formatUnknownError(err) });
97
101
  return;
98
102
  }
99
103
  if (reflection.status === "cooldown") {
@@ -116,7 +120,7 @@ async function runFeedbackReflection(params) {
116
120
  learning: reflection.learning
117
121
  });
118
122
  } catch (err) {
119
- log.debug?.("failed to store reflection learning", { error: require_setup_surface.formatUnknownError(err) });
123
+ log.debug?.("failed to store reflection learning", { error: require_channel_setup.formatUnknownError(err) });
120
124
  }
121
125
  const conversationType = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeOptionalLowercaseString)(params.conversationRef.conversation?.conversationType);
122
126
  if (!(conversationType === "personal" && reflection.followUp && Boolean(reflection.userMessage))) {
@@ -133,7 +137,7 @@ async function runFeedbackReflection(params) {
133
137
  }, { serviceUrlBoundary: require_resolve_allowlist.resolveMSTeamsSdkCloudOptions(cfg.channels?.msteams) });
134
138
  log.info("sent reflection follow-up", { sessionKey });
135
139
  } catch (err) {
136
- log.debug?.("failed to send reflection follow-up", { error: require_setup_surface.formatUnknownError(err) });
140
+ log.debug?.("failed to send reflection follow-up", { error: require_channel_setup.formatUnknownError(err) });
137
141
  }
138
142
  }
139
143
  //#endregion
@@ -166,6 +170,99 @@ function serializeMSTeamsAdaptiveCardActionValue(value) {
166
170
  }
167
171
  }
168
172
  //#endregion
173
+ //#region extensions/msteams/src/approval-card-submit.ts
174
+ function isMSTeamsApprovalSubmit(value) {
175
+ if (!(0, openclaw_plugin_sdk_string_coerce_runtime.isRecord)(value)) return false;
176
+ if (value.openclawAction === "approval") return true;
177
+ const data = ((0, openclaw_plugin_sdk_string_coerce_runtime.isRecord)(value.action) ? value.action : void 0)?.data;
178
+ return (0, openclaw_plugin_sdk_string_coerce_runtime.isRecord)(data) && data.openclawAction === "approval";
179
+ }
180
+ async function maybeHandleMSTeamsApprovalCardSubmit(params) {
181
+ const { context, deps } = params;
182
+ if (!isMSTeamsApprovalSubmit(context.activity.value)) return false;
183
+ const ignored = (reason) => deps.log.info("msteams approval ignored", { reason });
184
+ const token = require_approval_card.readMSTeamsApprovalActionToken(context.activity.value);
185
+ if (!token) {
186
+ ignored("missing card token");
187
+ return true;
188
+ }
189
+ const binding = require_approval_card.getMSTeamsApprovalCardBinding(token);
190
+ if (!binding) {
191
+ ignored("unknown or expired card token");
192
+ return true;
193
+ }
194
+ if (binding.accountId !== openclaw_plugin_sdk_account_id.DEFAULT_ACCOUNT_ID) {
195
+ ignored("card token account mismatch");
196
+ return true;
197
+ }
198
+ if (require_resolve_allowlist.normalizeMSTeamsConversationId(context.activity.conversation?.id ?? "") !== require_resolve_allowlist.normalizeMSTeamsConversationId(binding.conversationId)) {
199
+ ignored("card token conversation mismatch");
200
+ return true;
201
+ }
202
+ if (context.activity.replyToId && context.activity.replyToId !== binding.activityId) {
203
+ ignored("card token activity mismatch");
204
+ return true;
205
+ }
206
+ if (!binding.allowedDecisions.includes(binding.decision)) {
207
+ ignored("card token decision is no longer allowed");
208
+ return true;
209
+ }
210
+ const senderId = context.activity.from?.aadObjectId;
211
+ if (!(require_thread_session.msTeamsApprovalAuth.authorizeActorAction?.({
212
+ cfg: deps.cfg,
213
+ accountId: openclaw_plugin_sdk_account_id.DEFAULT_ACCOUNT_ID,
214
+ senderId,
215
+ action: "approve",
216
+ approvalKind: binding.approvalKind
217
+ }))?.authorized) {
218
+ ignored(`unauthorized actor ${senderId || "unknown"}`);
219
+ return true;
220
+ }
221
+ const claim = require_approval_card.claimMSTeamsApprovalCardBinding(token);
222
+ if (claim.kind !== "claimed") {
223
+ ignored(claim.kind === "in-flight" ? "card token resolve already in flight" : "card token already consumed");
224
+ return true;
225
+ }
226
+ const consumed = claim.binding;
227
+ let result;
228
+ try {
229
+ result = await (0, openclaw_plugin_sdk_approval_gateway_runtime.resolveApprovalOverGateway)({
230
+ cfg: deps.cfg,
231
+ approvalId: consumed.approvalId,
232
+ approvalKind: consumed.approvalKind,
233
+ decision: consumed.decision,
234
+ channel: "msteams",
235
+ accountId: openclaw_plugin_sdk_account_id.DEFAULT_ACCOUNT_ID,
236
+ senderId
237
+ });
238
+ await context.updateActivity({
239
+ type: "message",
240
+ id: consumed.activityId,
241
+ attachments: [{
242
+ contentType: "application/vnd.microsoft.card.adaptive",
243
+ content: require_approval_card.buildMSTeamsCanonicalApprovalTerminalCard(result)
244
+ }]
245
+ });
246
+ } catch (error) {
247
+ if ((0, openclaw_plugin_sdk_error_runtime.isApprovalNotFoundError)(error)) {
248
+ require_approval_card.completeMSTeamsApprovalCardBinding(token);
249
+ ignored(`approval expired or no longer exists id=${consumed.approvalId}`);
250
+ return true;
251
+ }
252
+ require_approval_card.releaseMSTeamsApprovalCardBinding(token);
253
+ throw error;
254
+ }
255
+ require_approval_card.completeMSTeamsApprovalCardBinding(token);
256
+ deps.log.info("msteams approval resolved", {
257
+ approvalId: consumed.approvalId,
258
+ approvalKind: consumed.approvalKind,
259
+ applied: result.applied,
260
+ status: result.approval.status,
261
+ senderId
262
+ });
263
+ return true;
264
+ }
265
+ //#endregion
169
266
  //#region extensions/msteams/src/monitor-handler/access.ts
170
267
  const msteamsIngressIdentity = {
171
268
  key: "sender-id",
@@ -331,7 +428,7 @@ async function admitMSTeamsMessage(params) {
331
428
  });
332
429
  if (senderAccess.decision === "pairing") {
333
430
  params.conversationStore.upsert(params.conversationId, params.conversationRef).catch((err) => {
334
- params.log.debug?.("failed to save conversation reference", { error: require_setup_surface.formatUnknownError(err) });
431
+ params.log.debug?.("failed to save conversation reference", { error: require_channel_setup.formatUnknownError(err) });
335
432
  });
336
433
  if (await pairing.upsertPairingRequest({
337
434
  id: senderId,
@@ -417,7 +514,7 @@ async function admitMSTeamsMessage(params) {
417
514
  return null;
418
515
  }
419
516
  params.conversationStore.upsert(params.conversationId, params.conversationRef).catch((err) => {
420
- params.log.debug?.("failed to save conversation reference", { error: require_setup_surface.formatUnknownError(err) });
517
+ params.log.debug?.("failed to save conversation reference", { error: require_channel_setup.formatUnknownError(err) });
421
518
  });
422
519
  return {
423
520
  ...access,
@@ -1593,7 +1690,7 @@ async function prepareMSTeamsInboundContent(params) {
1593
1690
  })
1594
1691
  });
1595
1692
  } catch (err) {
1596
- params.log.debug?.("failed to resolve inbound Teams media", { error: require_setup_surface.formatUnknownError(err) });
1693
+ params.log.debug?.("failed to resolve inbound Teams media", { error: require_channel_setup.formatUnknownError(err) });
1597
1694
  }
1598
1695
  const inboundMedia = mergeMSTeamsMediaFacts(params.advertisedMedia, mediaList);
1599
1696
  const nativeMediaForComparison = [...params.advertisedMedia, ...mediaList.slice(params.advertisedMedia.length).map((media) => ({
@@ -2135,15 +2232,16 @@ function createMSTeamsReplyDispatcher(params) {
2135
2232
  });
2136
2233
  };
2137
2234
  const queueDeliveryFailureSystemEvent = (failure) => {
2138
- const classification = require_setup_surface.classifyMSTeamsSendError(failure.error);
2139
- const errorText = require_setup_surface.formatUnknownError(failure.error);
2235
+ const classification = require_channel_setup.classifyMSTeamsSendError(failure.error);
2236
+ const errorText = require_channel_setup.formatUnknownError(failure.error);
2140
2237
  const failedAll = failure.failed >= failure.total;
2238
+ const ambiguous = classification.kind === "ambiguous";
2141
2239
  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"}.`,
2240
+ `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`}.`,
2241
+ ambiguous ? void 0 : `The user may not have received ${failedAll ? "that reply" : "the full reply"}.`,
2144
2242
  `Error: ${errorText}.`,
2145
2243
  classification.statusCode != null ? `Status: ${classification.statusCode}.` : void 0,
2146
- classification.kind === "transient" || classification.kind === "throttled" ? "Retrying later may succeed." : void 0
2244
+ require_channel_setup.formatMSTeamsDeliveryFailureGuidance(classification)
2147
2245
  ].filter(Boolean);
2148
2246
  core.system.enqueueSystemEvent(sentences.join(" "), {
2149
2247
  sessionKey: params.sessionKey,
@@ -2236,7 +2334,7 @@ function createMSTeamsReplyDispatcher(params) {
2236
2334
  if (sentIds.length > 0) try {
2237
2335
  params.onSentMessageIds?.(sentIds);
2238
2336
  } catch (error) {
2239
- params.log.warn?.("failed to record sent Teams message ids", { error: require_setup_surface.formatUnknownError(error) });
2337
+ params.log.warn?.("failed to record sent Teams message ids", { error: require_channel_setup.formatUnknownError(error) });
2240
2338
  }
2241
2339
  }
2242
2340
  };
@@ -2268,9 +2366,9 @@ function createMSTeamsReplyDispatcher(params) {
2268
2366
  };
2269
2367
  },
2270
2368
  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);
2369
+ const errMsg = require_channel_setup.formatUnknownError(err);
2370
+ const classification = require_channel_setup.classifyMSTeamsSendError(err);
2371
+ const hint = require_channel_setup.formatMSTeamsSendErrorHint(classification);
2274
2372
  params.runtime.error?.(`msteams ${info.kind} reply failed: ${errMsg}${hint ? ` (${hint})` : ""}`);
2275
2373
  params.log.error("reply failed", {
2276
2374
  kind: info.kind,
@@ -2314,7 +2412,7 @@ function createMSTeamsReplyDispatcher(params) {
2314
2412
  if (nativeResult.messageId) try {
2315
2413
  params.onSentMessageIds?.([nativeResult.messageId]);
2316
2414
  } catch (error) {
2317
- params.log.warn?.("failed to record sent Teams message id", { error: require_setup_surface.formatUnknownError(error) });
2415
+ params.log.warn?.("failed to record sent Teams message id", { error: require_channel_setup.formatUnknownError(error) });
2318
2416
  }
2319
2417
  };
2320
2418
  const previewToolProgressEnabled = (0, openclaw_plugin_sdk_channel_outbound.resolveChannelStreamingPreviewToolProgress)(msteamsCfg, true, teamsStreamMode);
@@ -2643,7 +2741,7 @@ async function dispatchMSTeamsInboundTurn(params) {
2643
2741
  },
2644
2742
  ctxPayload,
2645
2743
  record: { onRecordError: (err) => {
2646
- logVerboseMessage(`msteams: failed updating session meta: ${require_setup_surface.formatUnknownError(err)}`);
2744
+ logVerboseMessage(`msteams: failed updating session meta: ${require_channel_setup.formatUnknownError(err)}`);
2647
2745
  } },
2648
2746
  history: {
2649
2747
  isGroup: isRoomish,
@@ -2662,18 +2760,15 @@ async function dispatchMSTeamsInboundTurn(params) {
2662
2760
  });
2663
2761
  const dispatchResult = turnResult.dispatched ? turnResult.dispatchResult : void 0;
2664
2762
  const counts = (0, openclaw_plugin_sdk_channel_inbound.resolveInboundReplyDispatchCounts)(dispatchResult);
2665
- log.info("dispatch complete", {
2666
- queuedFinal: dispatchResult?.queuedFinal ?? false,
2667
- counts
2668
- });
2763
+ log.info("dispatch complete", { counts });
2669
2764
  if ((0, openclaw_plugin_sdk_channel_inbound.hasFinalInboundReplyDispatch)(dispatchResult)) logVerboseMessage(`msteams: delivered ${counts.final} repl${counts.final === 1 ? "y" : "ies"} to ${teamsTo}`);
2670
2765
  return {
2671
2766
  kind: "completed",
2672
2767
  finalResponses: counts.final
2673
2768
  };
2674
2769
  } catch (err) {
2675
- log.error("dispatch failed", { error: require_setup_surface.formatUnknownError(err) });
2676
- runtime.error(`msteams dispatch failed: ${require_setup_surface.formatUnknownError(err)}`);
2770
+ log.error("dispatch failed", { error: require_channel_setup.formatUnknownError(err) });
2771
+ runtime.error(`msteams dispatch failed: ${require_channel_setup.formatUnknownError(err)}`);
2677
2772
  if (facts.turnAdoptionLifecycle) throw err;
2678
2773
  try {
2679
2774
  await context.sendActivity("⚠️ Something went wrong. Please try again.");
@@ -2844,7 +2939,7 @@ function resolveParentCacheExpiresAt(nowRaw) {
2844
2939
  * Uses the injected `fetchParent` (defaults to `fetchChannelMessage`) so
2845
2940
  * tests can swap in a stub without mocking the Graph transport.
2846
2941
  */
2847
- async function fetchParentMessageCached(token, groupId, channelId, parentId, fetchParent = require_messenger.fetchChannelMessage) {
2942
+ async function fetchParentMessageCached(token, groupId, channelId, parentId, fetchParent = require_reaction_types.fetchChannelMessage) {
2848
2943
  const key = buildParentCacheKey(groupId, channelId, parentId);
2849
2944
  const now = (0, openclaw_plugin_sdk_number_runtime.asDateTimestampMs)(Date.now());
2850
2945
  const cached = parentCache.get(key);
@@ -2874,7 +2969,7 @@ function summarizeParentMessage(message) {
2874
2969
  const sender = message.from?.user?.displayName ?? message.from?.application?.displayName ?? "unknown";
2875
2970
  const contentType = message.body?.contentType ?? "text";
2876
2971
  const raw = message.body?.content ?? "";
2877
- const text = contentType === "html" ? require_messenger.stripHtmlFromTeamsMessage(raw) : raw.replace(/\s+/g, " ").trim();
2972
+ const text = contentType === "html" ? require_reaction_types.stripHtmlFromTeamsMessage(raw) : raw.replace(/\s+/g, " ").trim();
2878
2973
  if (!text) return;
2879
2974
  return {
2880
2975
  sender,
@@ -2918,7 +3013,7 @@ function prepareMSTeamsThreadRouting(params) {
2918
3013
  id: params.isDirectMessage ? params.senderId : params.conversationId
2919
3014
  }
2920
3015
  });
2921
- route.sessionKey = require_channel.resolveMSTeamsRouteSessionKey({
3016
+ route.sessionKey = require_thread_session.resolveMSTeamsRouteSessionKey({
2922
3017
  baseSessionKey: route.sessionKey,
2923
3018
  isChannel: params.isChannel,
2924
3019
  conversationMessageId: params.conversationMessageId,
@@ -2938,7 +3033,7 @@ function prepareMSTeamsThreadRouting(params) {
2938
3033
  }).catch((err) => {
2939
3034
  params.log.debug?.("failed to resolve Teams AAD group ID", {
2940
3035
  teamId: conversationTeamId,
2941
- error: require_setup_surface.formatUnknownError(err)
3036
+ error: require_channel_setup.formatUnknownError(err)
2942
3037
  });
2943
3038
  });
2944
3039
  teamAadGroupId = await teamGroupIdPromise;
@@ -2969,10 +3064,10 @@ async function resolveMSTeamsThreadContext(params) {
2969
3064
  quoteBodyFull = await require_resolve_allowlist.withMSTeamsRequestDeadline({
2970
3065
  deadline,
2971
3066
  label: "MS Teams quote lookup",
2972
- work: () => require_messenger.fetchChatMessageText(graphToken, params.conversationId, quoteMessageId, deadline)
3067
+ work: () => require_reaction_types.fetchChatMessageText(graphToken, params.conversationId, quoteMessageId, deadline)
2973
3068
  });
2974
3069
  } catch (err) {
2975
- params.log.debug?.("failed to fetch full quoted message text", { error: require_setup_surface.formatUnknownError(err) });
3070
+ params.log.debug?.("failed to fetch full quoted message text", { error: require_channel_setup.formatUnknownError(err) });
2976
3071
  }
2977
3072
  let threadContext;
2978
3073
  const threadParentId = activity.replyToId;
@@ -2985,12 +3080,12 @@ async function resolveMSTeamsThreadContext(params) {
2985
3080
  const [parentResult, repliesResult] = await require_resolve_allowlist.withMSTeamsRequestDeadline({
2986
3081
  deadline,
2987
3082
  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)])
3083
+ 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
3084
  });
2990
3085
  const parentMsg = parentResult.status === "fulfilled" ? parentResult.value : void 0;
2991
3086
  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) });
3087
+ if (parentResult.status === "rejected") params.log.debug?.("failed to fetch parent message", { error: require_channel_setup.formatUnknownError(parentResult.reason) });
3088
+ if (repliesResult.status === "rejected") params.log.debug?.("failed to fetch thread replies", { error: require_channel_setup.formatUnknownError(repliesResult.reason) });
2994
3089
  const isThreadSenderAllowed = (message) => (0, openclaw_plugin_sdk_channel_inbound.resolveInboundSupplementalSenderAllowed)({
2995
3090
  isGroup: params.isChannel,
2996
3091
  groupPolicy: params.groupPolicy,
@@ -3025,9 +3120,9 @@ async function resolveMSTeamsThreadContext(params) {
3025
3120
  kind: "thread",
3026
3121
  isSenderAllowed: isThreadSenderAllowed
3027
3122
  });
3028
- threadContext = require_messenger.formatThreadContext(threadMessages, activity.id) || void 0;
3123
+ threadContext = require_reaction_types.formatThreadContext(threadMessages, activity.id) || void 0;
3029
3124
  } catch (err) {
3030
- params.log.debug?.("failed to fetch thread history", { error: require_setup_surface.formatUnknownError(err) });
3125
+ params.log.debug?.("failed to fetch thread history", { error: require_channel_setup.formatUnknownError(err) });
3031
3126
  }
3032
3127
  quoteSenderName ??= params.quoteInfo?.sender;
3033
3128
  return {
@@ -3106,7 +3201,7 @@ function createMSTeamsMessageHandler(deps) {
3106
3201
  } catch (err) {
3107
3202
  log.error("failed to record poll vote", {
3108
3203
  pollId: pollVote.pollId,
3109
- error: require_setup_surface.formatUnknownError(err)
3204
+ error: require_channel_setup.formatUnknownError(err)
3110
3205
  });
3111
3206
  }
3112
3207
  return;
@@ -3283,7 +3378,7 @@ function createMSTeamsMessageHandler(deps) {
3283
3378
  });
3284
3379
  },
3285
3380
  onError: (err) => {
3286
- runtime.error(`msteams debounce flush failed: ${require_setup_surface.formatUnknownError(err)}`);
3381
+ runtime.error(`msteams debounce flush failed: ${require_channel_setup.formatUnknownError(err)}`);
3287
3382
  }
3288
3383
  });
3289
3384
  return async function handleTeamsMessage(context, turnAdoptionLifecycle) {
@@ -3307,7 +3402,8 @@ function createMSTeamsReactionHandler(deps) {
3307
3402
  const msteamsCfg = cfg.channels?.msteams;
3308
3403
  return async function handleReaction(context, direction) {
3309
3404
  const activity = context.activity;
3310
- const reactions = direction === "added" ? activity.reactionsAdded ?? [] : activity.reactionsRemoved ?? [];
3405
+ const rawReactions = direction === "added" ? activity.reactionsAdded : activity.reactionsRemoved;
3406
+ const reactions = Array.isArray(rawReactions) ? rawReactions : [];
3311
3407
  if (reactions.length === 0) {
3312
3408
  log.debug?.("reaction activity has no reactions; skipping");
3313
3409
  return;
@@ -3350,7 +3446,7 @@ function createMSTeamsReactionHandler(deps) {
3350
3446
  const targetMessageId = activity.replyToId ?? "unknown";
3351
3447
  for (const reaction of reactions) {
3352
3448
  const reactionType = reaction.type ?? "unknown";
3353
- const emoji = require_messenger.resolveMSTeamsReactionEmoji(reactionType);
3449
+ const emoji = require_reaction_types.resolveMSTeamsReactionEmoji(reactionType);
3354
3450
  const label = direction === "added" ? `Teams reaction ${emoji} added by ${senderName} on message ${targetMessageId}` : `Teams reaction ${emoji} removed by ${senderName} from message ${targetMessageId}`;
3355
3451
  log.info(`reaction ${direction}`, {
3356
3452
  sender: senderId,
@@ -3492,6 +3588,10 @@ function registerMSTeamsHandlers(handler, deps) {
3492
3588
  if (originalRun) handler.run = async (context, turnAdoptionLifecycle) => {
3493
3589
  const ctx = context;
3494
3590
  if (ctx.activity?.type === "invoke" && ctx.activity?.name === "adaptiveCard/action") {
3591
+ if (await maybeHandleMSTeamsApprovalCardSubmit({
3592
+ context: ctx,
3593
+ deps
3594
+ })) return;
3495
3595
  const text = serializeMSTeamsAdaptiveCardActionValue(ctx.activity?.value);
3496
3596
  if (text) return await handleTeamsMessage({
3497
3597
  ...ctx,
@@ -3512,12 +3612,20 @@ function registerMSTeamsHandlers(handler, deps) {
3512
3612
  await next();
3513
3613
  };
3514
3614
  try {
3515
- const result = await handleTeamsMessage(context, turnAdoptionLifecycle);
3615
+ const ctx = context;
3616
+ if (await maybeHandleMSTeamsApprovalCardSubmit({
3617
+ context: ctx,
3618
+ deps
3619
+ })) {
3620
+ await runNext();
3621
+ return;
3622
+ }
3623
+ const result = await handleTeamsMessage(ctx, turnAdoptionLifecycle);
3516
3624
  await runNext();
3517
3625
  return result;
3518
3626
  } catch (err) {
3519
3627
  if (turnAdoptionLifecycle) throw err;
3520
- deps.runtime.error(`msteams handler failed: ${require_setup_surface.formatUnknownError(err)}`);
3628
+ deps.runtime.error(`msteams handler failed: ${require_channel_setup.formatUnknownError(err)}`);
3521
3629
  }
3522
3630
  if (!nextRan) await runNext();
3523
3631
  });
@@ -3543,7 +3651,7 @@ function registerMSTeamsHandlers(handler, deps) {
3543
3651
  });
3544
3652
  deps.log.info("sent welcome card");
3545
3653
  } catch (err) {
3546
- deps.log.debug?.("failed to send welcome card", { error: require_setup_surface.formatUnknownError(err) });
3654
+ deps.log.debug?.("failed to send welcome card", { error: require_channel_setup.formatUnknownError(err) });
3547
3655
  }
3548
3656
  } else if (!isPersonal && msteamsCfg?.groupWelcomeCard === true) {
3549
3657
  const botName = ctx.activity?.recipient?.name ?? void 0;
@@ -3551,7 +3659,7 @@ function registerMSTeamsHandlers(handler, deps) {
3551
3659
  await ctx.sendActivity(buildGroupWelcomeText(botName));
3552
3660
  deps.log.info("sent group welcome message");
3553
3661
  } catch (err) {
3554
- deps.log.debug?.("failed to send group welcome", { error: require_setup_surface.formatUnknownError(err) });
3662
+ deps.log.debug?.("failed to send group welcome", { error: require_channel_setup.formatUnknownError(err) });
3555
3663
  }
3556
3664
  } else deps.log.debug?.("skipping welcome (disabled by config or conversation type)");
3557
3665
  } else deps.log.debug?.("member added", { member: member.id });
@@ -3687,7 +3795,7 @@ async function runMSTeamsFeedbackInvokeHandler(context, deps) {
3687
3795
  userComment,
3688
3796
  log: deps.log
3689
3797
  }).catch((err) => {
3690
- deps.log.error("feedback reflection failed", { error: require_setup_surface.formatUnknownError(err) });
3798
+ deps.log.error("feedback reflection failed", { error: require_channel_setup.formatUnknownError(err) });
3691
3799
  });
3692
3800
  return true;
3693
3801
  }
@@ -3764,7 +3872,7 @@ async function handleMSTeamsFileConsentInvoke(context, log) {
3764
3872
  } catch (err) {
3765
3873
  log.error("file upload failed", {
3766
3874
  uploadId,
3767
- error: require_setup_surface.formatUnknownError(err)
3875
+ error: require_channel_setup.formatUnknownError(err)
3768
3876
  });
3769
3877
  await context.sendActivity("File upload failed. Please try again.");
3770
3878
  } finally {
@@ -3797,7 +3905,7 @@ async function runMSTeamsFileConsentInvokeHandler(context, log) {
3797
3905
  }
3798
3906
  });
3799
3907
  } catch (err) {
3800
- log.debug?.("file consent handler error", { error: require_setup_surface.formatUnknownError(err) });
3908
+ log.debug?.("file consent handler error", { error: require_channel_setup.formatUnknownError(err) });
3801
3909
  }
3802
3910
  }
3803
3911
  //#endregion
@@ -3902,7 +4010,7 @@ function createMSTeamsIngress(options) {
3902
4010
  reason: error.reason,
3903
4011
  message: error.message
3904
4012
  };
3905
- return require_setup_surface.classifyMSTeamsSendError(error).kind === "auth" ? {
4013
+ return require_channel_setup.classifyMSTeamsSendError(error).kind === "auth" ? {
3906
4014
  reason: "authentication-failed",
3907
4015
  message: (0, openclaw_plugin_sdk_error_runtime.formatErrorMessage)(error)
3908
4016
  } : null;
@@ -3955,6 +4063,54 @@ function createMSTeamsIngress(options) {
3955
4063
  };
3956
4064
  }
3957
4065
  //#endregion
4066
+ //#region extensions/msteams/src/replay-context.ts
4067
+ function createMSTeamsReplayContext(activity, app, serviceUrlBoundary) {
4068
+ const rawConversationId = activity.conversation?.id ?? "";
4069
+ const conversationId = require_resolve_allowlist.normalizeMSTeamsConversationId(rawConversationId);
4070
+ const conversationType = activity.conversation?.conversationType ?? "personal";
4071
+ const normalizedConversationType = conversationType.toLowerCase();
4072
+ const threadActivityId = normalizedConversationType === "channel" ? require_resolve_allowlist.extractMSTeamsConversationMessageId(rawConversationId) ?? activity.replyToId : void 0;
4073
+ const quoteActivityId = normalizedConversationType === "channel" || normalizedConversationType === "groupchat" ? activity.id : void 0;
4074
+ const tenantId = activity.channelData?.tenant?.id ?? activity.conversation?.tenantId;
4075
+ const reference = {
4076
+ activityId: activity.id,
4077
+ user: activity.from,
4078
+ agent: activity.recipient,
4079
+ conversation: {
4080
+ id: conversationId,
4081
+ conversationType,
4082
+ ...tenantId ? { tenantId } : {}
4083
+ },
4084
+ channelId: activity.channelId,
4085
+ serviceUrl: activity.serviceUrl,
4086
+ locale: activity.locale,
4087
+ ...tenantId ? { tenantId } : {},
4088
+ ...activity.from?.aadObjectId ? { aadObjectId: activity.from.aadObjectId } : {}
4089
+ };
4090
+ const proactiveOptions = {
4091
+ ...quoteActivityId ? { quoteActivityId } : {},
4092
+ ...threadActivityId ? { threadActivityId } : {},
4093
+ serviceUrlBoundary
4094
+ };
4095
+ const sendActivity = (outbound) => require_messenger.sendMSTeamsActivityWithReference(app, reference, outbound, proactiveOptions);
4096
+ return {
4097
+ activity,
4098
+ sendActivity,
4099
+ sendActivities: async (activities) => {
4100
+ const results = [];
4101
+ for (const outbound of activities) results.push(await sendActivity(outbound));
4102
+ return results;
4103
+ },
4104
+ updateActivity: async (outbound) => {
4105
+ return await require_messenger.updateMSTeamsActivityWithReference(app, reference, typeof outbound.id === "string" ? outbound.id : "", outbound, proactiveOptions);
4106
+ },
4107
+ deleteActivity: async (activityId) => {
4108
+ await require_messenger.deleteMSTeamsActivityWithReference(app, reference, activityId, proactiveOptions);
4109
+ },
4110
+ getTeamDetails: (teamId) => app.api.teams.getById(teamId)
4111
+ };
4112
+ }
4113
+ //#endregion
3958
4114
  //#region extensions/msteams/src/webhook-timeouts.ts
3959
4115
  const MSTEAMS_WEBHOOK_INACTIVITY_TIMEOUT_MS = 3e4;
3960
4116
  const MSTEAMS_WEBHOOK_REQUEST_TIMEOUT_MS = 3e4;
@@ -4059,7 +4215,7 @@ async function monitorMSTeamsProvider(opts) {
4059
4215
  (0, openclaw_plugin_sdk_allow_from.summarizeMapping)("msteams channels", resolved.mapping, resolved.unresolved, runtime);
4060
4216
  }
4061
4217
  } catch (err) {
4062
- runtime.error?.(`msteams resolve failed; mutable allowlist entries are disabled. ${require_setup_surface.formatUnknownError(err)}`);
4218
+ runtime.error?.(`msteams resolve failed; mutable allowlist entries are disabled. ${require_channel_setup.formatUnknownError(err)}`);
4063
4219
  }
4064
4220
  if (configuredGroupAllowFrom == null && groupAllowFrom) groupAllowFrom = (0, openclaw_plugin_sdk_allow_from.mergeAllowlist)({
4065
4221
  existing: groupAllowFrom,
@@ -4213,7 +4369,7 @@ async function monitorMSTeamsProvider(opts) {
4213
4369
  } catch (err) {
4214
4370
  log.error("failed to record poll vote", {
4215
4371
  pollId: vote.pollId,
4216
- error: require_setup_surface.formatUnknownError(err)
4372
+ error: require_channel_setup.formatUnknownError(err)
4217
4373
  });
4218
4374
  return {
4219
4375
  statusCode: 500,
@@ -4236,7 +4392,7 @@ async function monitorMSTeamsProvider(opts) {
4236
4392
  value: "OK"
4237
4393
  };
4238
4394
  } catch (err) {
4239
- log.error("msteams card.action failed", { error: require_setup_surface.formatUnknownError(err) });
4395
+ log.error("msteams card.action failed", { error: require_channel_setup.formatUnknownError(err) });
4240
4396
  return {
4241
4397
  statusCode: 500,
4242
4398
  type: "application/vnd.microsoft.error",
@@ -4304,7 +4460,7 @@ async function monitorMSTeamsProvider(opts) {
4304
4460
  hasExpiry: Boolean(ctx.token.expiration)
4305
4461
  });
4306
4462
  })().catch((err) => {
4307
- log.error("msteams sso token persistence failed", { error: require_setup_surface.formatUnknownError(err) });
4463
+ log.error("msteams sso token persistence failed", { error: require_channel_setup.formatUnknownError(err) });
4308
4464
  });
4309
4465
  });
4310
4466
  app.on("message.submit", async (ctx) => {
@@ -4325,7 +4481,7 @@ async function monitorMSTeamsProvider(opts) {
4325
4481
  try {
4326
4482
  await handler.run(adaptedCtx);
4327
4483
  } catch (err) {
4328
- log.error("msteams non-turn activity failed", { error: require_setup_surface.formatUnknownError(err) });
4484
+ log.error("msteams non-turn activity failed", { error: require_channel_setup.formatUnknownError(err) });
4329
4485
  }
4330
4486
  });
4331
4487
  await app.initialize();
@@ -4335,7 +4491,7 @@ async function monitorMSTeamsProvider(opts) {
4335
4491
  const onListen = (err) => err ? reject(err) : resolve(server);
4336
4492
  const server = privateQaRuntime ? expressApp.listen(port, privateQaRuntime.listenHost, onListen) : expressApp.listen(port, onListen);
4337
4493
  }).catch(async (err) => {
4338
- log.error("msteams server error", { error: require_setup_surface.formatUnknownError(err) });
4494
+ log.error("msteams server error", { error: require_channel_setup.formatUnknownError(err) });
4339
4495
  await ingress.stop();
4340
4496
  throw err;
4341
4497
  });
@@ -4343,14 +4499,14 @@ async function monitorMSTeamsProvider(opts) {
4343
4499
  publishMSTeamsReady(opts.statusSink);
4344
4500
  applyMSTeamsWebhookTimeouts(httpServer);
4345
4501
  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));
4502
+ log.error("msteams server error", { error: require_channel_setup.formatUnknownError(err) });
4503
+ publishMSTeamsRecovering(opts.statusSink, require_channel_setup.formatUnknownError(err));
4348
4504
  });
4349
4505
  const shutdown = async () => {
4350
4506
  log.info("shutting down msteams provider");
4351
4507
  await new Promise((resolve) => {
4352
4508
  httpServer.close((err) => {
4353
- if (err) log.debug?.("msteams server close error", { error: require_setup_surface.formatUnknownError(err) });
4509
+ if (err) log.debug?.("msteams server close error", { error: require_channel_setup.formatUnknownError(err) });
4354
4510
  resolve();
4355
4511
  });
4356
4512
  });
@@ -4411,47 +4567,6 @@ function buildActivityHandler() {
4411
4567
  };
4412
4568
  return handler;
4413
4569
  }
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
4570
  /**
4456
4571
  * Adapt a new @microsoft/teams.apps SDK context to the MSTeamsTurnContext interface
4457
4572
  * our handlers expect. The new SDK uses reply()/send() instead of sendActivity().