@openclaw/msteams 2026.7.2-beta.7 → 2026.8.1-beta.3

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,3 +1,3 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_channel = require("./channel-C7QxRjBW.cjs");
2
+ const require_channel = require("./channel-KpWENcgK.cjs");
3
3
  exports.msteamsPlugin = require_channel.msteamsPlugin;
@@ -1,10 +1,10 @@
1
- const require_polls = require("./polls-BWKNpBSg.cjs");
2
1
  const require_runtime = require("./runtime-gZTAuFux.cjs");
3
2
  require("./runtime-api.cjs");
4
- const require_resolve_allowlist = require("./resolve-allowlist-CEj9sABO.cjs");
5
- const require_channel = require("./channel-C7QxRjBW.cjs");
6
- const require_setup_surface = require("./setup-surface-ByWjaXEn.cjs");
7
- const require_messenger = require("./messenger-DTiaLTDO.cjs");
3
+ const require_resolve_allowlist = require("./resolve-allowlist-CIfWUwuc.cjs");
4
+ const require_channel = require("./channel-KpWENcgK.cjs");
5
+ const require_channel_setup = require("./channel.setup-mOFtsfYz.cjs");
6
+ const require_polls = require("./polls-DvuJvaDG.cjs");
7
+ const require_messenger = require("./messenger-IISPSOvj.cjs");
8
8
  let openclaw_plugin_sdk_channel_outbound = require("openclaw/plugin-sdk/channel-outbound");
9
9
  let openclaw_plugin_sdk_string_coerce_runtime = require("openclaw/plugin-sdk/string-coerce-runtime");
10
10
  let openclaw_plugin_sdk_reply_payload = require("openclaw/plugin-sdk/reply-payload");
@@ -165,9 +165,10 @@ async function pinMessageMSTeams(params) {
165
165
  const body = { "message@odata.bind": `https://graph.microsoft.com/v1.0/chats/${encodeURIComponent(conversationId)}/messages/${encodeURIComponent(params.messageId)}` };
166
166
  return {
167
167
  ok: true,
168
- pinnedMessageId: (await require_resolve_allowlist.postGraphJson({
168
+ pinnedMessageId: (await require_resolve_allowlist.mutateGraphJson({
169
169
  token,
170
170
  path: `${conv.basePath}/pinnedMessages`,
171
+ method: "POST",
171
172
  body
172
173
  })).id
173
174
  };
@@ -239,10 +240,12 @@ async function reactMessageMSTeams(params) {
239
240
  const reactionType = require_messenger.resolveMSTeamsReactionEmoji(params.reactionType);
240
241
  const token = await require_resolve_allowlist.resolveGraphToken(params.cfg, { preferDelegated: true });
241
242
  const { basePath } = resolveConversationPath(await resolveGraphConversationId(params.to));
242
- await require_resolve_allowlist.postGraphBetaJson({
243
+ await require_resolve_allowlist.mutateGraphJson({
243
244
  token,
244
245
  path: `${basePath}/messages/${encodeURIComponent(params.messageId)}/setReaction`,
245
- body: { reactionType }
246
+ method: "POST",
247
+ body: { reactionType },
248
+ beta: true
246
249
  });
247
250
  return { ok: true };
248
251
  }
@@ -256,10 +259,12 @@ async function unreactMessageMSTeams(params) {
256
259
  const reactionType = require_messenger.resolveMSTeamsReactionEmoji(params.reactionType);
257
260
  const token = await require_resolve_allowlist.resolveGraphToken(params.cfg, { preferDelegated: true });
258
261
  const { basePath } = resolveConversationPath(await resolveGraphConversationId(params.to));
259
- await require_resolve_allowlist.postGraphBetaJson({
262
+ await require_resolve_allowlist.mutateGraphJson({
260
263
  token,
261
264
  path: `${basePath}/messages/${encodeURIComponent(params.messageId)}/unsetReaction`,
262
- body: { reactionType }
265
+ method: "POST",
266
+ body: { reactionType },
267
+ beta: true
263
268
  });
264
269
  return { ok: true };
265
270
  }
@@ -411,9 +416,10 @@ async function addParticipantMSTeams(params) {
411
416
  roles: resolveConversationMemberRoles(params.role, conv.kind),
412
417
  "user@odata.bind": `https://graph.microsoft.com/v1.0/users('${require_resolve_allowlist.escapeOData(params.userId)}')`
413
418
  };
414
- await require_resolve_allowlist.postGraphJson({
419
+ await require_resolve_allowlist.mutateGraphJson({
415
420
  token,
416
421
  path: `${conv.basePath}/members`,
422
+ method: "POST",
417
423
  body
418
424
  });
419
425
  return { added: {
@@ -450,9 +456,10 @@ async function renameGroupMSTeams(params) {
450
456
  const conversationId = await resolveGraphConversationId(params.to);
451
457
  const conv = resolveConversationPath(conversationId);
452
458
  const body = conv.kind === "chat" ? { topic: params.name } : { displayName: params.name };
453
- await require_resolve_allowlist.patchGraphJson({
459
+ await require_resolve_allowlist.mutateGraphJson({
454
460
  token,
455
461
  path: conv.basePath,
462
+ method: "PATCH",
456
463
  body
457
464
  });
458
465
  return { renamed: {
@@ -571,9 +578,9 @@ async function getChannelInfoMSTeams(params) {
571
578
  }
572
579
  //#endregion
573
580
  //#region extensions/msteams/src/send-context.ts
574
- function resolveMSTeamsProactiveReplyStyle(params) {
581
+ function resolveMSTeamsProactiveReplyTarget(params) {
575
582
  const threadRootId = params.ref.threadId ?? params.ref.activityId;
576
- if (params.conversationType !== "channel" || !threadRootId) return "top-level";
583
+ if (params.conversationType !== "channel" || !threadRootId) return { replyStyle: "top-level" };
577
584
  const routeConfig = require_channel.resolveMSTeamsRouteConfig({
578
585
  cfg: params.cfg,
579
586
  teamId: params.ref.teamId,
@@ -586,12 +593,16 @@ function resolveMSTeamsProactiveReplyStyle(params) {
586
593
  teamConfig: routeConfig.teamConfig,
587
594
  channelConfig: routeConfig.channelConfig
588
595
  });
589
- return replyStyle;
596
+ return replyStyle === "thread" ? {
597
+ replyStyle,
598
+ threadActivityId: threadRootId
599
+ } : { replyStyle };
590
600
  }
591
601
  /**
592
602
  * Parse the target value into a conversation reference lookup key.
593
603
  * Supported formats:
594
604
  * - conversation:19:abc@thread.tacv2 → lookup by conversation ID
605
+ * - conversation:19:abc@thread.tacv2;messageid=root → lookup base ID, use root
595
606
  * - user:aad-object-id → lookup by user AAD object ID
596
607
  * - 19:abc@thread.tacv2 → direct conversation ID
597
608
  */
@@ -600,6 +611,17 @@ function parseRecipient(to) {
600
611
  const finalize = (type, id) => {
601
612
  const normalized = id.trim();
602
613
  if (!normalized) throw new Error(`Invalid target value: missing ${type} id`);
614
+ if (type === "conversation") {
615
+ const threadId = require_resolve_allowlist.extractMSTeamsConversationMessageId(normalized);
616
+ const normalizedConversationId = require_resolve_allowlist.normalizeMSTeamsConversationId(normalized);
617
+ const slashIndex = normalizedConversationId.indexOf("/");
618
+ const graphChannelId = slashIndex > 0 ? normalizedConversationId.slice(slashIndex + 1) : void 0;
619
+ return {
620
+ type,
621
+ id: graphChannelId && (graphChannelId.startsWith("19:") || graphChannelId.includes("@thread")) ? graphChannelId : normalizedConversationId,
622
+ ...threadId ? { threadId } : {}
623
+ };
624
+ }
603
625
  return {
604
626
  type,
605
627
  id: normalized
@@ -632,6 +654,9 @@ async function findConversationReference(recipient) {
632
654
  async function resolveMSTeamsSendContext(params) {
633
655
  const msteamsCfg = params.cfg.channels?.msteams;
634
656
  if (!msteamsCfg?.enabled) throw new Error("msteams provider is not enabled");
657
+ const account = require_channel_setup.resolveMSTeamsAccount(params.cfg);
658
+ if (account.tokenStatus === "configured_unavailable") throw new Error("msteams credential file is configured but unavailable");
659
+ if (!account.configured) throw new Error("msteams credentials not configured");
635
660
  const creds = require_resolve_allowlist.resolveMSTeamsCredentials(msteamsCfg);
636
661
  if (!creds) throw new Error("msteams credentials not configured");
637
662
  const store = require_polls.createMSTeamsConversationStoreState();
@@ -641,7 +666,11 @@ async function resolveMSTeamsSendContext(params) {
641
666
  store
642
667
  });
643
668
  if (!found) throw new Error(`No conversation reference found for ${recipient.type}:${recipient.id}. The bot must receive a message from this conversation before it can send proactively.`);
644
- const { conversationId, ref } = found;
669
+ const conversationId = found.conversationId;
670
+ const ref = recipient.threadId ? {
671
+ ...found.ref,
672
+ threadId: recipient.threadId
673
+ } : found.ref;
645
674
  const log = require_runtime.getMSTeamsRuntime().logging.getChildLogger({ name: "msteams:send" });
646
675
  if (ref.serviceUrl && !require_resolve_allowlist.isAllowedBotFrameworkServiceUrl(ref.serviceUrl)) {
647
676
  try {
@@ -649,7 +678,7 @@ async function resolveMSTeamsSendContext(params) {
649
678
  } catch (err) {
650
679
  log.warn?.("failed to remove blocked msteams conversation reference", {
651
680
  conversationId,
652
- error: require_setup_surface.formatUnknownError(err)
681
+ error: require_channel_setup.formatUnknownError(err)
653
682
  });
654
683
  }
655
684
  throw new Error(`Stored Microsoft Teams conversation reference has blocked serviceUrl host: ${require_resolve_allowlist.describeBotFrameworkServiceUrlHost(ref.serviceUrl)}. The bot must receive a new message from this conversation before it can send proactively.`);
@@ -676,7 +705,10 @@ async function resolveMSTeamsSendContext(params) {
676
705
  if (storedConversationType === "personal") conversationType = "personal";
677
706
  else if (storedConversationType === "channel") conversationType = "channel";
678
707
  else conversationType = "groupChat";
679
- const replyStyle = resolveMSTeamsProactiveReplyStyle({
708
+ const replyTarget = recipient.threadId && conversationType === "channel" ? {
709
+ replyStyle: "thread",
710
+ threadActivityId: recipient.threadId
711
+ } : resolveMSTeamsProactiveReplyTarget({
680
712
  cfg: msteamsCfg,
681
713
  conversationId,
682
714
  ref: safeRef,
@@ -694,7 +726,7 @@ async function resolveMSTeamsSendContext(params) {
694
726
  app,
695
727
  log,
696
728
  conversationType,
697
- replyStyle,
729
+ ...replyTarget,
698
730
  sdkCloudOptions,
699
731
  tokenProvider,
700
732
  sharePointSiteId,
@@ -761,7 +793,7 @@ function createMSTeamsSendResult(params) {
761
793
  * - Group chats / channels: files require configured SharePoint storage
762
794
  */
763
795
  async function sendMessageMSTeams(params) {
764
- const { cfg, to, text, mediaUrl, filename, mediaLocalRoots, mediaReadFile } = params;
796
+ const { cfg, to, text, mediaUrl, filename, mediaAccess, mediaLocalRoots, mediaReadFile } = params;
765
797
  const tableMode = (0, openclaw_plugin_sdk_markdown_table_runtime.resolveMarkdownTableMode)({
766
798
  cfg,
767
799
  channel: "msteams"
@@ -771,7 +803,7 @@ async function sendMessageMSTeams(params) {
771
803
  cfg,
772
804
  to
773
805
  });
774
- const { app, conversationId, ref, log, conversationType, replyStyle, tokenProvider, sharePointSiteId, sdkCloudOptions } = ctx;
806
+ const { conversationId, log, conversationType, tokenProvider, sharePointSiteId } = ctx;
775
807
  log.debug?.("sending proactive message", {
776
808
  conversationId,
777
809
  conversationType,
@@ -781,6 +813,7 @@ async function sendMessageMSTeams(params) {
781
813
  if (mediaUrl) {
782
814
  const media = await (0, openclaw_plugin_sdk_outbound_media.loadOutboundMediaFromUrl)(mediaUrl, {
783
815
  maxBytes: ctx.mediaMaxBytes ?? MSTEAMS_MAX_MEDIA_BYTES,
816
+ mediaAccess,
784
817
  mediaLocalRoots,
785
818
  mediaReadFile
786
819
  });
@@ -817,11 +850,9 @@ async function sendMessageMSTeams(params) {
817
850
  size: media.buffer.length
818
851
  });
819
852
  const messageId = await sendProactiveActivity({
820
- app,
821
- ref,
853
+ ctx,
822
854
  activity,
823
- errorPrefix: "msteams consent card send",
824
- serviceUrlBoundary: sdkCloudOptions
855
+ errorPrefix: "msteams consent card send"
825
856
  });
826
857
  require_messenger.setPendingUploadActivityId(uploadId, messageId);
827
858
  await require_messenger.setPendingUploadActivityIdFs(uploadId, messageId);
@@ -876,15 +907,12 @@ async function sendMessageMSTeams(params) {
876
907
  });
877
908
  const fileCardAttachment = require_messenger.buildTeamsFileInfoCard(driveItem);
878
909
  const messageId = await sendProactiveActivityRaw({
879
- app,
880
- ref,
910
+ ctx,
881
911
  activity: {
882
912
  type: "message",
883
913
  text: messageText || void 0,
884
914
  attachments: [fileCardAttachment]
885
- },
886
- threadActivityId: replyStyle === "thread" && conversationType === "channel" ? ref.threadId ?? ref.activityId : void 0,
887
- serviceUrlBoundary: sdkCloudOptions
915
+ }
888
916
  });
889
917
  log.info("sent native file card", {
890
918
  conversationId,
@@ -897,10 +925,10 @@ async function sendMessageMSTeams(params) {
897
925
  kind: "media"
898
926
  });
899
927
  } catch (err) {
900
- const classification = require_setup_surface.classifyMSTeamsSendError(err);
901
- const hint = require_setup_surface.formatMSTeamsSendErrorHint(classification);
928
+ const classification = require_channel_setup.classifyMSTeamsSendError(err);
929
+ const hint = require_channel_setup.formatMSTeamsSendErrorHint(classification);
902
930
  const status = classification.statusCode ? ` (HTTP ${classification.statusCode})` : "";
903
- throw new Error(`msteams file send failed${status}: ${require_setup_surface.formatUnknownError(err)}${hint ? ` (${hint})` : ""}`, { cause: err });
931
+ throw new Error(`msteams file send failed${status}: ${require_channel_setup.formatUnknownError(err)}${hint ? ` (${hint})` : ""}`, { cause: err });
904
932
  }
905
933
  }
906
934
  return sendTextWithMedia(ctx, messageText, void 0);
@@ -935,10 +963,10 @@ async function sendTextWithMedia(ctx, text, mediaUrl) {
935
963
  serviceUrlBoundary: ctx.sdkCloudOptions
936
964
  });
937
965
  } catch (err) {
938
- const classification = require_setup_surface.classifyMSTeamsSendError(err);
939
- const hint = require_setup_surface.formatMSTeamsSendErrorHint(classification);
966
+ const classification = require_channel_setup.classifyMSTeamsSendError(err);
967
+ const hint = require_channel_setup.formatMSTeamsSendErrorHint(classification);
940
968
  const status = classification.statusCode ? ` (HTTP ${classification.statusCode})` : "";
941
- throw new Error(`msteams send failed${status}: ${require_setup_surface.formatUnknownError(err)}${hint ? ` (${hint})` : ""}`, { cause: err });
969
+ throw new Error(`msteams send failed${status}: ${require_channel_setup.formatUnknownError(err)}${hint ? ` (${hint})` : ""}`, { cause: err });
942
970
  }
943
971
  const messageId = platformMessageIds[0] ?? "unknown";
944
972
  log.info("sent proactive message", {
@@ -956,25 +984,24 @@ async function sendTextWithMedia(ctx, text, mediaUrl) {
956
984
  })
957
985
  };
958
986
  }
959
- async function sendProactiveActivityRaw({ app, ref, activity, threadActivityId, serviceUrlBoundary }) {
960
- return require_messenger.extractMessageId(await require_messenger.sendMSTeamsActivityWithReference(app, require_messenger.buildConversationReference(ref), activity, {
961
- ...threadActivityId ? { threadActivityId } : {},
962
- serviceUrlBoundary
987
+ async function sendProactiveActivityRaw({ ctx, activity }) {
988
+ const baseRef = require_messenger.buildConversationReference(ctx.ref);
989
+ return require_messenger.extractMessageId(await require_messenger.sendMSTeamsActivityWithReference(ctx.app, baseRef, activity, {
990
+ ...ctx.threadActivityId ? { threadActivityId: ctx.threadActivityId } : {},
991
+ serviceUrlBoundary: ctx.sdkCloudOptions
963
992
  })) ?? "unknown";
964
993
  }
965
- async function sendProactiveActivity({ app, ref, activity, errorPrefix, serviceUrlBoundary }) {
994
+ async function sendProactiveActivity({ ctx, activity, errorPrefix }) {
966
995
  try {
967
996
  return await sendProactiveActivityRaw({
968
- app,
969
- ref,
970
- activity,
971
- serviceUrlBoundary
997
+ ctx,
998
+ activity
972
999
  });
973
1000
  } catch (err) {
974
- const classification = require_setup_surface.classifyMSTeamsSendError(err);
975
- const hint = require_setup_surface.formatMSTeamsSendErrorHint(classification);
1001
+ const classification = require_channel_setup.classifyMSTeamsSendError(err);
1002
+ const hint = require_channel_setup.formatMSTeamsSendErrorHint(classification);
976
1003
  const status = classification.statusCode ? ` (HTTP ${classification.statusCode})` : "";
977
- throw new Error(`${errorPrefix} failed${status}: ${require_setup_surface.formatUnknownError(err)}${hint ? ` (${hint})` : ""}`, { cause: err });
1004
+ throw new Error(`${errorPrefix} failed${status}: ${require_channel_setup.formatUnknownError(err)}${hint ? ` (${hint})` : ""}`, { cause: err });
978
1005
  }
979
1006
  }
980
1007
  /**
@@ -982,10 +1009,11 @@ async function sendProactiveActivity({ app, ref, activity, errorPrefix, serviceU
982
1009
  */
983
1010
  async function sendPollMSTeams(params) {
984
1011
  const { cfg, to, question, options, maxSelections } = params;
985
- const { app, conversationId, ref, log, sdkCloudOptions } = await resolveMSTeamsSendContext({
1012
+ const ctx = await resolveMSTeamsSendContext({
986
1013
  cfg,
987
1014
  to
988
1015
  });
1016
+ const { conversationId, log } = ctx;
989
1017
  const pollCard = require_polls.buildMSTeamsPollCard({
990
1018
  question,
991
1019
  options,
@@ -997,8 +1025,7 @@ async function sendPollMSTeams(params) {
997
1025
  optionCount: pollCard.options.length
998
1026
  });
999
1027
  const messageId = await sendProactiveActivity({
1000
- app,
1001
- ref,
1028
+ ctx,
1002
1029
  activity: {
1003
1030
  type: "message",
1004
1031
  attachments: [{
@@ -1006,8 +1033,7 @@ async function sendPollMSTeams(params) {
1006
1033
  content: pollCard.card
1007
1034
  }]
1008
1035
  },
1009
- errorPrefix: "msteams poll send",
1010
- serviceUrlBoundary: sdkCloudOptions
1036
+ errorPrefix: "msteams poll send"
1011
1037
  });
1012
1038
  log.info("sent poll", {
1013
1039
  conversationId,
@@ -1025,18 +1051,18 @@ async function sendPollMSTeams(params) {
1025
1051
  */
1026
1052
  async function sendAdaptiveCardMSTeams(params) {
1027
1053
  const { cfg, to, card } = params;
1028
- const { app, conversationId, ref, log, sdkCloudOptions } = await resolveMSTeamsSendContext({
1054
+ const ctx = await resolveMSTeamsSendContext({
1029
1055
  cfg,
1030
1056
  to
1031
1057
  });
1058
+ const { conversationId, log } = ctx;
1032
1059
  log.debug?.("sending adaptive card", {
1033
1060
  conversationId,
1034
1061
  cardType: card.type,
1035
1062
  cardVersion: card.version
1036
1063
  });
1037
1064
  const messageId = await sendProactiveActivity({
1038
- app,
1039
- ref,
1065
+ ctx,
1040
1066
  activity: {
1041
1067
  type: "message",
1042
1068
  attachments: [{
@@ -1044,8 +1070,7 @@ async function sendAdaptiveCardMSTeams(params) {
1044
1070
  content: card
1045
1071
  }]
1046
1072
  },
1047
- errorPrefix: "msteams card send",
1048
- serviceUrlBoundary: sdkCloudOptions
1073
+ errorPrefix: "msteams card send"
1049
1074
  });
1050
1075
  log.info("sent adaptive card", {
1051
1076
  conversationId,
@@ -1080,10 +1105,10 @@ async function editMessageMSTeams(params) {
1080
1105
  text
1081
1106
  }, { serviceUrlBoundary: sdkCloudOptions });
1082
1107
  } catch (err) {
1083
- const classification = require_setup_surface.classifyMSTeamsSendError(err);
1084
- const hint = require_setup_surface.formatMSTeamsSendErrorHint(classification);
1108
+ const classification = require_channel_setup.classifyMSTeamsSendError(err);
1109
+ const hint = require_channel_setup.formatMSTeamsSendErrorHint(classification);
1085
1110
  const status = classification.statusCode ? ` (HTTP ${classification.statusCode})` : "";
1086
- throw new Error(`msteams edit failed${status}: ${require_setup_surface.formatUnknownError(err)}${hint ? ` (${hint})` : ""}`, { cause: err });
1111
+ throw new Error(`msteams edit failed${status}: ${require_channel_setup.formatUnknownError(err)}${hint ? ` (${hint})` : ""}`, { cause: err });
1087
1112
  }
1088
1113
  log.info("edited proactive message", {
1089
1114
  conversationId,
@@ -1110,10 +1135,10 @@ async function deleteMessageMSTeams(params) {
1110
1135
  try {
1111
1136
  await require_messenger.deleteMSTeamsActivityWithReference(app, require_messenger.buildConversationReference(ref), activityId, { serviceUrlBoundary: sdkCloudOptions });
1112
1137
  } catch (err) {
1113
- const classification = require_setup_surface.classifyMSTeamsSendError(err);
1114
- const hint = require_setup_surface.formatMSTeamsSendErrorHint(classification);
1138
+ const classification = require_channel_setup.classifyMSTeamsSendError(err);
1139
+ const hint = require_channel_setup.formatMSTeamsSendErrorHint(classification);
1115
1140
  const status = classification.statusCode ? ` (HTTP ${classification.statusCode})` : "";
1116
- throw new Error(`msteams delete failed${status}: ${require_setup_surface.formatUnknownError(err)}${hint ? ` (${hint})` : ""}`, { cause: err });
1141
+ throw new Error(`msteams delete failed${status}: ${require_channel_setup.formatUnknownError(err)}${hint ? ` (${hint})` : ""}`, { cause: err });
1117
1142
  }
1118
1143
  log.info("deleted proactive message", {
1119
1144
  conversationId,
@@ -1127,6 +1152,23 @@ const MSTEAMS_TEXT_CHUNK_LIMIT = 4e3;
1127
1152
  function resolveMSTeamsEffectiveTextChunkLimit(configuredLimit) {
1128
1153
  return typeof configuredLimit === "number" && configuredLimit > 0 ? Math.min(configuredLimit, MSTEAMS_TEXT_CHUNK_LIMIT) : MSTEAMS_TEXT_CHUNK_LIMIT;
1129
1154
  }
1155
+ function toMSTeamsOutboundResult(result) {
1156
+ const { conversationId, ...delivery } = result;
1157
+ return {
1158
+ ...delivery,
1159
+ target: {
1160
+ kind: "conversation",
1161
+ id: conversationId
1162
+ }
1163
+ };
1164
+ }
1165
+ function resolveMSTeamsThreadTarget(to, threadId) {
1166
+ const normalizedThreadId = threadId == null ? "" : String(threadId).trim();
1167
+ const graphChannelId = to.includes("/") ? to.slice(to.indexOf("/") + 1) : "";
1168
+ const isConversationTarget = to.startsWith("conversation:") || to.startsWith("19:") || graphChannelId.startsWith("19:") || graphChannelId.includes("@thread");
1169
+ if (!normalizedThreadId || /(?:^|;)messageid=/iu.test(to) || !isConversationTarget) return to;
1170
+ return `${to};messageid=${normalizedThreadId}`;
1171
+ }
1130
1172
  function resolveMSTeamsTextSend(params) {
1131
1173
  return (0, openclaw_plugin_sdk_channel_outbound.resolveOutboundSendDep)(params.deps, "msteams") ?? ((to, text) => sendMessageMSTeams({
1132
1174
  cfg: params.cfg,
@@ -1139,9 +1181,7 @@ function resolveMSTeamsMediaSend(params) {
1139
1181
  cfg: params.cfg,
1140
1182
  to,
1141
1183
  text,
1142
- mediaUrl: opts?.mediaUrl,
1143
- mediaLocalRoots: opts?.mediaLocalRoots,
1144
- mediaReadFile: opts?.mediaReadFile
1184
+ ...opts
1145
1185
  }));
1146
1186
  }
1147
1187
  const msteamsOutbound = {
@@ -1176,13 +1216,14 @@ const msteamsOutbound = {
1176
1216
  }
1177
1217
  };
1178
1218
  },
1179
- sendPayload: async ({ cfg, to, text, mediaUrl, mediaLocalRoots, mediaReadFile, payload, deps, onDeliveryResult }) => {
1219
+ sendPayload: async ({ cfg, to, text, mediaUrl, mediaAccess, mediaLocalRoots, mediaReadFile, payload, deps, onDeliveryResult, threadId }) => {
1220
+ const deliveryTarget = resolveMSTeamsThreadTarget(to, threadId);
1180
1221
  const presentationCard = (0, openclaw_plugin_sdk_string_coerce_runtime.asOptionalRecord)(payload.channelData?.msteams)?.presentationCard;
1181
- if (presentationCard && typeof presentationCard === "object" && !Array.isArray(presentationCard)) return (0, openclaw_plugin_sdk_channel_send_result.attachChannelToResult)("msteams", await sendAdaptiveCardMSTeams({
1222
+ if (presentationCard && typeof presentationCard === "object" && !Array.isArray(presentationCard)) return (0, openclaw_plugin_sdk_channel_send_result.attachChannelToResult)("msteams", toMSTeamsOutboundResult(await sendAdaptiveCardMSTeams({
1182
1223
  cfg,
1183
- to,
1224
+ to: deliveryTarget,
1184
1225
  card: presentationCard
1185
- }));
1226
+ })));
1186
1227
  const mediaUrls = (0, openclaw_plugin_sdk_string_normalization_runtime.normalizeStringEntries)((0, openclaw_plugin_sdk_reply_payload.resolvePayloadMediaUrls)({
1187
1228
  ...payload,
1188
1229
  mediaUrl: payload.mediaUrl ?? mediaUrl
@@ -1196,15 +1237,16 @@ const msteamsOutbound = {
1196
1237
  text,
1197
1238
  mediaUrls,
1198
1239
  onResult: async (deliveryResult) => {
1199
- await onDeliveryResult?.((0, openclaw_plugin_sdk_channel_send_result.attachChannelToResult)("msteams", deliveryResult));
1240
+ await onDeliveryResult?.((0, openclaw_plugin_sdk_channel_send_result.attachChannelToResult)("msteams", toMSTeamsOutboundResult(deliveryResult)));
1200
1241
  },
1201
- send: async ({ text: textLocal, mediaUrl: mediaUrlLocal }) => await send(to, textLocal, {
1242
+ send: async ({ text: textLocal, mediaUrl: mediaUrlLocal }) => await send(deliveryTarget, textLocal, {
1202
1243
  mediaUrl: mediaUrlLocal,
1244
+ mediaAccess,
1203
1245
  mediaLocalRoots,
1204
1246
  mediaReadFile
1205
1247
  })
1206
1248
  });
1207
- if (result) return (0, openclaw_plugin_sdk_channel_send_result.attachChannelToResult)("msteams", result);
1249
+ if (result) return (0, openclaw_plugin_sdk_channel_send_result.attachChannelToResult)("msteams", toMSTeamsOutboundResult(result));
1208
1250
  }
1209
1251
  if (text.trim()) {
1210
1252
  const send = resolveMSTeamsTextSend({
@@ -1214,36 +1256,37 @@ const msteamsOutbound = {
1214
1256
  const chunks = (0, openclaw_plugin_sdk_reply_payload.resolveTextChunksWithFallback)(text, (0, openclaw_plugin_sdk_text_chunking.chunkTextForOutbound)(text, resolveMSTeamsEffectiveTextChunkLimit(cfg.channels?.msteams?.textChunkLimit)));
1215
1257
  let result;
1216
1258
  for (const chunk of chunks) {
1217
- result = await send(to, chunk);
1218
- await onDeliveryResult?.((0, openclaw_plugin_sdk_channel_send_result.attachChannelToResult)("msteams", result));
1259
+ result = await send(deliveryTarget, chunk);
1260
+ await onDeliveryResult?.((0, openclaw_plugin_sdk_channel_send_result.attachChannelToResult)("msteams", toMSTeamsOutboundResult(result)));
1219
1261
  }
1220
- return (0, openclaw_plugin_sdk_channel_send_result.attachChannelToResult)("msteams", result);
1262
+ return (0, openclaw_plugin_sdk_channel_send_result.attachChannelToResult)("msteams", toMSTeamsOutboundResult(result));
1221
1263
  }
1222
1264
  throw new Error("MS Teams payload send requires text, media, or a presentation card.");
1223
1265
  },
1224
1266
  ...(0, openclaw_plugin_sdk_channel_send_result.createAttachedChannelResultAdapter)({
1225
1267
  channel: "msteams",
1226
- sendText: async ({ cfg, to, text, deps }) => {
1227
- return await resolveMSTeamsTextSend({
1268
+ sendText: async ({ cfg, to, text, deps, threadId }) => {
1269
+ return toMSTeamsOutboundResult(await resolveMSTeamsTextSend({
1228
1270
  cfg,
1229
1271
  deps
1230
- })(to, text);
1272
+ })(resolveMSTeamsThreadTarget(to, threadId), text));
1231
1273
  },
1232
- sendMedia: async ({ cfg, to, text, mediaUrl, mediaLocalRoots, mediaReadFile, deps }) => {
1233
- return await resolveMSTeamsMediaSend({
1274
+ sendMedia: async ({ cfg, to, text, mediaUrl, mediaAccess, mediaLocalRoots, mediaReadFile, deps, threadId }) => {
1275
+ return toMSTeamsOutboundResult(await resolveMSTeamsMediaSend({
1234
1276
  cfg,
1235
1277
  deps
1236
- })(to, text, {
1278
+ })(resolveMSTeamsThreadTarget(to, threadId), text, {
1237
1279
  mediaUrl,
1280
+ mediaAccess,
1238
1281
  mediaLocalRoots,
1239
1282
  mediaReadFile
1240
- });
1283
+ }));
1241
1284
  },
1242
- sendPoll: async ({ cfg, to, poll }) => {
1285
+ sendPoll: async ({ cfg, to, poll, threadId }) => {
1243
1286
  const maxSelections = poll.maxSelections ?? 1;
1244
1287
  const result = await sendPollMSTeams({
1245
1288
  cfg,
1246
- to,
1289
+ to: resolveMSTeamsThreadTarget(to, threadId),
1247
1290
  question: poll.question,
1248
1291
  options: poll.options,
1249
1292
  maxSelections
@@ -1315,7 +1358,7 @@ async function probeMSTeams(cfg) {
1315
1358
  } catch (err) {
1316
1359
  graph = {
1317
1360
  ok: false,
1318
- error: require_setup_surface.formatUnknownError(err)
1361
+ error: require_channel_setup.formatUnknownError(err)
1319
1362
  };
1320
1363
  }
1321
1364
  let delegatedAuth;
@@ -1349,7 +1392,7 @@ async function probeMSTeams(cfg) {
1349
1392
  return {
1350
1393
  ok: false,
1351
1394
  appId: creds.appId,
1352
- error: require_setup_surface.formatUnknownError(err)
1395
+ error: require_channel_setup.formatUnknownError(err)
1353
1396
  };
1354
1397
  }
1355
1398
  }