@openclaw/msteams 2026.8.1-beta.3 → 2026.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/dist/{adapter.runtime-8g-MOPfb.cjs → adapter.runtime-DDuc7sKJ.cjs} +1 -1
  2. package/dist/api.cjs +2 -2
  3. package/dist/approval-card-BEblaIto.cjs +303 -0
  4. package/dist/approval-handler.runtime-C0AWNWXk.cjs +107 -0
  5. package/dist/{channel-KpWENcgK.cjs → channel-DLn4b6Qi.cjs} +168 -53
  6. package/dist/channel-config-api.cjs +1 -1
  7. package/dist/channel-plugin-api.cjs +1 -1
  8. package/dist/{channel.runtime-Bkzj8jZ0.cjs → channel.runtime-1mH99ZAm.cjs} +49 -608
  9. package/dist/{channel.setup-mOFtsfYz.cjs → channel.setup-BRbhaigB.cjs} +29 -18
  10. package/dist/{config-schema-C4CszdDi.cjs → config-schema-MyN2lamA.cjs} +12 -11
  11. package/dist/configured-state.cjs +20 -0
  12. package/dist/directory-contract-api.cjs +1 -1
  13. package/dist/doctor-contract-api.cjs +79 -42
  14. package/dist/{messenger-IISPSOvj.cjs → messenger-flkiAkkB.cjs} +29 -171
  15. package/dist/{oauth-C9So7uld.cjs → oauth-Bctn-WPI.cjs} +4 -3
  16. package/dist/{polls-DvuJvaDG.cjs → polls-P86qBpeV.cjs} +5 -4
  17. package/dist/qa-runner-api.cjs +1 -1
  18. package/dist/reaction-types-CL79V_5D.cjs +150 -0
  19. package/dist/{resolve-allowlist-CIfWUwuc.cjs → resolve-allowlist-BrdWKHE-.cjs} +26 -51
  20. package/dist/{rolldown-runtime-D6vf50IK.cjs → rolldown-runtime-VH7oDXx4.cjs} +1 -1
  21. package/dist/runtime-api.cjs +2 -1
  22. package/dist/secret-input-C65t6kjM.cjs +1 -0
  23. package/dist/send-C4BjzS1F.cjs +631 -0
  24. package/dist/setup-plugin-api.cjs +1 -1
  25. package/dist/{src-C127-DcQ.cjs → src-RSjkJRjI.cjs} +237 -99
  26. package/dist/{sso-token-store-ChhO1f4i.cjs → sso-token-store-CNbRhz-A.cjs} +1 -1
  27. package/dist/thread-session-DxOri69r.cjs +63 -0
  28. package/package.json +13 -11
@@ -1,28 +1,27 @@
1
- const require_runtime = require("./runtime-gZTAuFux.cjs");
2
1
  require("./runtime-api.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");
2
+ const require_resolve_allowlist = require("./resolve-allowlist-BrdWKHE-.cjs");
3
+ const require_channel = require("./channel-DLn4b6Qi.cjs");
4
+ const require_channel_setup = require("./channel.setup-BRbhaigB.cjs");
5
+ const require_polls = require("./polls-P86qBpeV.cjs");
6
+ const require_send = require("./send-C4BjzS1F.cjs");
7
+ const require_reaction_types = require("./reaction-types-CL79V_5D.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");
11
11
  let openclaw_plugin_sdk_number_runtime = require("openclaw/plugin-sdk/number-runtime");
12
12
  let openclaw_plugin_sdk_channel_send_result = require("openclaw/plugin-sdk/channel-send-result");
13
- let openclaw_plugin_sdk_markdown_table_runtime = require("openclaw/plugin-sdk/markdown-table-runtime");
14
- let openclaw_plugin_sdk_media_runtime = require("openclaw/plugin-sdk/media-runtime");
15
- let openclaw_plugin_sdk_outbound_media = require("openclaw/plugin-sdk/outbound-media");
16
13
  let openclaw_plugin_sdk_text_chunking = require("openclaw/plugin-sdk/text-chunking");
17
14
  let openclaw_plugin_sdk_string_normalization_runtime = require("openclaw/plugin-sdk/string-normalization-runtime");
18
15
  //#region extensions/msteams/src/directory-live.ts
19
16
  async function listMSTeamsDirectoryPeersLive(params) {
20
17
  const query = require_resolve_allowlist.normalizeQuery(params.query);
21
18
  if (!query) return [];
19
+ const token = await require_resolve_allowlist.resolveGraphToken(params.cfg);
20
+ const limit = typeof params.limit === "number" && params.limit > 0 ? params.limit : 20;
22
21
  return (await require_resolve_allowlist.searchGraphUsers({
23
- token: await require_resolve_allowlist.resolveGraphToken(params.cfg),
22
+ token,
24
23
  query,
25
- top: typeof params.limit === "number" && params.limit > 0 ? params.limit : 20
24
+ top: limit
26
25
  })).map((user) => {
27
26
  const id = user.id?.trim();
28
27
  if (!id) return null;
@@ -135,9 +134,10 @@ function resolveConversationPath(to) {
135
134
  async function getMessageMSTeams(params) {
136
135
  const token = await require_resolve_allowlist.resolveGraphToken(params.cfg);
137
136
  const { basePath } = resolveConversationPath(await resolveGraphConversationId(params.to));
137
+ const path = `${basePath}/messages/${encodeURIComponent(params.messageId)}`;
138
138
  const msg = await require_resolve_allowlist.fetchGraphJson({
139
139
  token,
140
- path: `${basePath}/messages/${encodeURIComponent(params.messageId)}`
140
+ path
141
141
  });
142
142
  return {
143
143
  id: msg.id ?? params.messageId,
@@ -185,9 +185,10 @@ async function unpinMessageMSTeams(params) {
185
185
  const token = await require_resolve_allowlist.resolveGraphToken(params.cfg);
186
186
  const conv = resolveConversationPath(await resolveGraphConversationId(params.to));
187
187
  if (conv.kind === "channel") throw new Error("Pin/unpin is not supported for channel messages on Graph v1.0. Only chat conversations support pinned messages.");
188
+ const path = `${conv.basePath}/pinnedMessages/${encodeURIComponent(params.pinnedMessageId)}`;
188
189
  await require_resolve_allowlist.deleteGraphRequest({
189
190
  token,
190
- path: `${conv.basePath}/pinnedMessages/${encodeURIComponent(params.pinnedMessageId)}`
191
+ path
191
192
  });
192
193
  return { ok: true };
193
194
  }
@@ -237,12 +238,13 @@ async function listPinsMSTeams(params) {
237
238
  * delegated-auth-enabled deployments hit the user-scoped endpoint.
238
239
  */
239
240
  async function reactMessageMSTeams(params) {
240
- const reactionType = require_messenger.resolveMSTeamsReactionEmoji(params.reactionType);
241
+ const reactionType = require_reaction_types.resolveMSTeamsReactionEmoji(params.reactionType);
241
242
  const token = await require_resolve_allowlist.resolveGraphToken(params.cfg, { preferDelegated: true });
242
243
  const { basePath } = resolveConversationPath(await resolveGraphConversationId(params.to));
244
+ const path = `${basePath}/messages/${encodeURIComponent(params.messageId)}/setReaction`;
243
245
  await require_resolve_allowlist.mutateGraphJson({
244
246
  token,
245
- path: `${basePath}/messages/${encodeURIComponent(params.messageId)}/setReaction`,
247
+ path,
246
248
  method: "POST",
247
249
  body: { reactionType },
248
250
  beta: true
@@ -256,12 +258,13 @@ async function reactMessageMSTeams(params) {
256
258
  * `preferDelegated: true`. See `reactMessageMSTeams` for fallback rules.
257
259
  */
258
260
  async function unreactMessageMSTeams(params) {
259
- const reactionType = require_messenger.resolveMSTeamsReactionEmoji(params.reactionType);
261
+ const reactionType = require_reaction_types.resolveMSTeamsReactionEmoji(params.reactionType);
260
262
  const token = await require_resolve_allowlist.resolveGraphToken(params.cfg, { preferDelegated: true });
261
263
  const { basePath } = resolveConversationPath(await resolveGraphConversationId(params.to));
264
+ const path = `${basePath}/messages/${encodeURIComponent(params.messageId)}/unsetReaction`;
262
265
  await require_resolve_allowlist.mutateGraphJson({
263
266
  token,
264
- path: `${basePath}/messages/${encodeURIComponent(params.messageId)}/unsetReaction`,
267
+ path,
265
268
  method: "POST",
266
269
  body: { reactionType },
267
270
  beta: true
@@ -275,9 +278,10 @@ async function unreactMessageMSTeams(params) {
275
278
  async function listReactionsMSTeams(params) {
276
279
  const token = await require_resolve_allowlist.resolveGraphToken(params.cfg);
277
280
  const { basePath } = resolveConversationPath(await resolveGraphConversationId(params.to));
281
+ const path = `${basePath}/messages/${encodeURIComponent(params.messageId)}`;
278
282
  const msg = await require_resolve_allowlist.fetchGraphJson({
279
283
  token,
280
- path: `${basePath}/messages/${encodeURIComponent(params.messageId)}`
284
+ path
281
285
  });
282
286
  const grouped = /* @__PURE__ */ new Map();
283
287
  for (const reaction of msg.reactions ?? []) {
@@ -296,7 +300,7 @@ async function listReactionsMSTeams(params) {
296
300
  return { reactions: Array.from(grouped.entries()).map(([type, group]) => ({
297
301
  reactionType: type,
298
302
  name: type,
299
- emoji: require_messenger.getMSTeamsReactionEmoji(type),
303
+ emoji: require_reaction_types.getMSTeamsReactionEmoji(type),
300
304
  count: group.count,
301
305
  users: group.users
302
306
  })) };
@@ -307,7 +311,7 @@ const SEARCH_PAGE_SIZE = 50;
307
311
  const SEARCH_MAX_PAGES = 10;
308
312
  function normalizeSearchText(message) {
309
313
  const content = message.body?.content ?? "";
310
- return message.body?.contentType?.toLowerCase() === "html" ? require_messenger.stripHtmlFromTeamsMessage(content) : content.trim();
314
+ return message.body?.contentType?.toLowerCase() === "html" ? require_reaction_types.stripHtmlFromTeamsMessage(content) : content.trim();
311
315
  }
312
316
  function matchesSearchSender(message, from) {
313
317
  const normalized = from?.trim().toLowerCase();
@@ -358,7 +362,7 @@ async function searchMessagesMSTeams(params) {
358
362
  messages,
359
363
  truncated: false
360
364
  };
361
- truncated = page === SEARCH_MAX_PAGES - 1;
365
+ truncated = page === 9;
362
366
  }
363
367
  return {
364
368
  messages,
@@ -439,9 +443,10 @@ async function removeParticipantMSTeams(params) {
439
443
  userId: params.userId
440
444
  });
441
445
  if (!member?.id) throw new Error(`User ${params.userId} is not a member of this conversation`);
446
+ const conv = resolveConversationPath(conversationId);
442
447
  await require_resolve_allowlist.deleteGraphRequest({
443
448
  token,
444
- path: `${resolveConversationPath(conversationId).basePath}/members/${encodeURIComponent(member.id)}`
449
+ path: `${conv.basePath}/members/${encodeURIComponent(member.id)}`
445
450
  });
446
451
  return { removed: {
447
452
  userId: params.userId,
@@ -563,9 +568,11 @@ async function listChannelsMSTeams(params) {
563
568
  * Returns id, displayName, description, membershipType, webUrl, and createdDateTime.
564
569
  */
565
570
  async function getChannelInfoMSTeams(params) {
571
+ const token = await require_resolve_allowlist.resolveGraphToken(params.cfg);
572
+ const path = `/teams/${encodeURIComponent(params.teamId)}/channels/${encodeURIComponent(params.channelId)}?$select=id,displayName,description,membershipType,webUrl,createdDateTime`;
566
573
  const ch = await require_resolve_allowlist.fetchGraphJson({
567
- token: await require_resolve_allowlist.resolveGraphToken(params.cfg),
568
- path: `/teams/${encodeURIComponent(params.teamId)}/channels/${encodeURIComponent(params.channelId)}?$select=id,displayName,description,membershipType,webUrl,createdDateTime`
574
+ token,
575
+ path
569
576
  });
570
577
  return { channel: {
571
578
  id: ch.id,
@@ -577,576 +584,6 @@ async function getChannelInfoMSTeams(params) {
577
584
  } };
578
585
  }
579
586
  //#endregion
580
- //#region extensions/msteams/src/send-context.ts
581
- function resolveMSTeamsProactiveReplyTarget(params) {
582
- const threadRootId = params.ref.threadId ?? params.ref.activityId;
583
- if (params.conversationType !== "channel" || !threadRootId) return { replyStyle: "top-level" };
584
- const routeConfig = require_channel.resolveMSTeamsRouteConfig({
585
- cfg: params.cfg,
586
- teamId: params.ref.teamId,
587
- conversationId: params.conversationId,
588
- allowNameMatching: false
589
- });
590
- const { replyStyle } = require_channel.resolveMSTeamsReplyPolicy({
591
- isDirectMessage: false,
592
- globalConfig: params.cfg,
593
- teamConfig: routeConfig.teamConfig,
594
- channelConfig: routeConfig.channelConfig
595
- });
596
- return replyStyle === "thread" ? {
597
- replyStyle,
598
- threadActivityId: threadRootId
599
- } : { replyStyle };
600
- }
601
- /**
602
- * Parse the target value into a conversation reference lookup key.
603
- * Supported formats:
604
- * - conversation:19:abc@thread.tacv2 → lookup by conversation ID
605
- * - conversation:19:abc@thread.tacv2;messageid=root → lookup base ID, use root
606
- * - user:aad-object-id → lookup by user AAD object ID
607
- * - 19:abc@thread.tacv2 → direct conversation ID
608
- */
609
- function parseRecipient(to) {
610
- const trimmed = to.trim();
611
- const finalize = (type, id) => {
612
- const normalized = id.trim();
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
- }
625
- return {
626
- type,
627
- id: normalized
628
- };
629
- };
630
- if (trimmed.startsWith("conversation:")) return finalize("conversation", trimmed.slice(13));
631
- if (trimmed.startsWith("user:")) return finalize("user", trimmed.slice(5));
632
- if (trimmed.startsWith("19:") || trimmed.includes("@thread")) return finalize("conversation", trimmed);
633
- return finalize("user", trimmed);
634
- }
635
- /**
636
- * Find a stored conversation reference for the given recipient.
637
- */
638
- async function findConversationReference(recipient) {
639
- if (recipient.type === "conversation") {
640
- const ref = await recipient.store.get(recipient.id);
641
- if (ref) return {
642
- conversationId: recipient.id,
643
- ref
644
- };
645
- return null;
646
- }
647
- const found = await recipient.store.findPreferredDmByUserId(recipient.id);
648
- if (!found) return null;
649
- return {
650
- conversationId: found.conversationId,
651
- ref: found.reference
652
- };
653
- }
654
- async function resolveMSTeamsSendContext(params) {
655
- const msteamsCfg = params.cfg.channels?.msteams;
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");
660
- const creds = require_resolve_allowlist.resolveMSTeamsCredentials(msteamsCfg);
661
- if (!creds) throw new Error("msteams credentials not configured");
662
- const store = require_polls.createMSTeamsConversationStoreState();
663
- const recipient = parseRecipient(params.to);
664
- const found = await findConversationReference({
665
- ...recipient,
666
- store
667
- });
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.`);
669
- const conversationId = found.conversationId;
670
- const ref = recipient.threadId ? {
671
- ...found.ref,
672
- threadId: recipient.threadId
673
- } : found.ref;
674
- const log = require_runtime.getMSTeamsRuntime().logging.getChildLogger({ name: "msteams:send" });
675
- if (ref.serviceUrl && !require_resolve_allowlist.isAllowedBotFrameworkServiceUrl(ref.serviceUrl)) {
676
- try {
677
- await store.remove(conversationId);
678
- } catch (err) {
679
- log.warn?.("failed to remove blocked msteams conversation reference", {
680
- conversationId,
681
- error: require_channel_setup.formatUnknownError(err)
682
- });
683
- }
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.`);
685
- }
686
- const safeRef = ref.serviceUrl ? {
687
- ...ref,
688
- serviceUrl: require_resolve_allowlist.normalizeBotFrameworkServiceUrl(ref.serviceUrl)
689
- } : ref;
690
- if (recipient.type === "user") {
691
- const resolvedType = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeLowercaseStringOrEmpty)(safeRef.conversation?.conversationType ?? "");
692
- if (resolvedType && resolvedType !== "personal") throw new Error(`Conversation reference for user:${recipient.id} resolved to a ${resolvedType} conversation (${conversationId}) instead of a personal DM. The bot must receive a DM from this user before it can send proactively.`);
693
- }
694
- const sdkCloudOptions = require_resolve_allowlist.resolveMSTeamsSdkCloudOptions(msteamsCfg);
695
- const { app } = await require_resolve_allowlist.loadMSTeamsSdkWithAuth(creds, sdkCloudOptions);
696
- require_resolve_allowlist.validateMSTeamsProactiveServiceUrlBoundary({
697
- cloud: sdkCloudOptions.cloud,
698
- conversationId,
699
- storedServiceUrl: safeRef.serviceUrl,
700
- configuredServiceUrl: sdkCloudOptions.serviceUrl
701
- });
702
- const tokenProvider = require_resolve_allowlist.createMSTeamsTokenProvider(app);
703
- const storedConversationType = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeLowercaseStringOrEmpty)(safeRef.conversation?.conversationType ?? "");
704
- let conversationType;
705
- if (storedConversationType === "personal") conversationType = "personal";
706
- else if (storedConversationType === "channel") conversationType = "channel";
707
- else conversationType = "groupChat";
708
- const replyTarget = recipient.threadId && conversationType === "channel" ? {
709
- replyStyle: "thread",
710
- threadActivityId: recipient.threadId
711
- } : resolveMSTeamsProactiveReplyTarget({
712
- cfg: msteamsCfg,
713
- conversationId,
714
- ref: safeRef,
715
- conversationType
716
- });
717
- const sharePointSiteId = msteamsCfg.sharePointSiteId;
718
- const mediaMaxBytes = (0, openclaw_plugin_sdk_media_runtime.resolveChannelMediaMaxBytes)({
719
- cfg: params.cfg,
720
- resolveChannelLimitMb: ({ cfg }) => cfg.channels?.msteams?.mediaMaxMb
721
- });
722
- return {
723
- appId: creds.appId,
724
- conversationId,
725
- ref: safeRef,
726
- app,
727
- log,
728
- conversationType,
729
- ...replyTarget,
730
- sdkCloudOptions,
731
- tokenProvider,
732
- sharePointSiteId,
733
- mediaMaxBytes
734
- };
735
- }
736
- //#endregion
737
- //#region extensions/msteams/src/send.ts
738
- /** Threshold for large files that require FileConsentCard flow in personal chats */
739
- const FILE_CONSENT_THRESHOLD_BYTES = 4 * 1024 * 1024;
740
- /**
741
- * MSTeams-specific media size limit (100MB).
742
- * Higher than the default to support Teams file-consent and SharePoint uploads.
743
- */
744
- const MSTEAMS_MAX_MEDIA_BYTES = 100 * 1024 * 1024;
745
- function createMSTeamsSendReceipt(params) {
746
- const receipt = (0, openclaw_plugin_sdk_channel_outbound.createMessageReceiptFromOutboundResults)({
747
- kind: params.kind,
748
- results: params.platformMessageIds.map((messageId) => ({
749
- channel: "msteams",
750
- messageId,
751
- conversationId: params.conversationId
752
- }))
753
- });
754
- if (!params.kinds) return receipt;
755
- const kinds = params.kinds;
756
- return {
757
- ...receipt,
758
- parts: receipt.parts.map((part, index) => {
759
- const nextPart = {
760
- platformMessageId: part.platformMessageId,
761
- kind: kinds[index] ?? params.kind,
762
- index: part.index
763
- };
764
- if (part.threadId) nextPart.threadId = part.threadId;
765
- if (part.replyToId) nextPart.replyToId = part.replyToId;
766
- if (part.raw) nextPart.raw = part.raw;
767
- return nextPart;
768
- })
769
- };
770
- }
771
- function createMSTeamsSendResult(params) {
772
- const platformMessageIds = (params.platformMessageIds?.length ? [...params.platformMessageIds] : [params.messageId]).map((messageId) => messageId.trim()).filter((messageId) => messageId && messageId !== "unknown");
773
- return {
774
- messageId: params.messageId,
775
- conversationId: params.conversationId,
776
- receipt: createMSTeamsSendReceipt({
777
- conversationId: params.conversationId,
778
- platformMessageIds,
779
- kind: params.kind
780
- }),
781
- ...params.pendingUploadId ? { pendingUploadId: params.pendingUploadId } : {}
782
- };
783
- }
784
- /**
785
- * Send a message to a Teams conversation or user.
786
- *
787
- * Uses the stored ConversationReference from previous interactions.
788
- * The bot must have received at least one message from the conversation
789
- * before proactive messaging works.
790
- *
791
- * File handling by conversation type:
792
- * - Personal (1:1) chats: small images (<4MB) use base64, large files and non-images use FileConsentCard
793
- * - Group chats / channels: files require configured SharePoint storage
794
- */
795
- async function sendMessageMSTeams(params) {
796
- const { cfg, to, text, mediaUrl, filename, mediaAccess, mediaLocalRoots, mediaReadFile } = params;
797
- const tableMode = (0, openclaw_plugin_sdk_markdown_table_runtime.resolveMarkdownTableMode)({
798
- cfg,
799
- channel: "msteams"
800
- });
801
- const messageText = require_messenger.formatMSTeamsMarkdown(text ?? "", tableMode);
802
- const ctx = await resolveMSTeamsSendContext({
803
- cfg,
804
- to
805
- });
806
- const { conversationId, log, conversationType, tokenProvider, sharePointSiteId } = ctx;
807
- log.debug?.("sending proactive message", {
808
- conversationId,
809
- conversationType,
810
- textLength: messageText.length,
811
- hasMedia: Boolean(mediaUrl)
812
- });
813
- if (mediaUrl) {
814
- const media = await (0, openclaw_plugin_sdk_outbound_media.loadOutboundMediaFromUrl)(mediaUrl, {
815
- maxBytes: ctx.mediaMaxBytes ?? MSTEAMS_MAX_MEDIA_BYTES,
816
- mediaAccess,
817
- mediaLocalRoots,
818
- mediaReadFile
819
- });
820
- const isLargeFile = media.buffer.length >= FILE_CONSENT_THRESHOLD_BYTES;
821
- const isImage = media.contentType?.startsWith("image/") ?? false;
822
- const fallbackFileName = await require_messenger.extractFilename(mediaUrl);
823
- const fileName = filename?.trim() || media.fileName || fallbackFileName;
824
- log.debug?.("processing media", {
825
- fileName,
826
- contentType: media.contentType,
827
- size: media.buffer.length,
828
- isLargeFile,
829
- isImage,
830
- conversationType
831
- });
832
- if (require_messenger.requiresFileConsent({
833
- conversationType,
834
- contentType: media.contentType,
835
- bufferSize: media.buffer.length,
836
- thresholdBytes: FILE_CONSENT_THRESHOLD_BYTES
837
- })) {
838
- const { activity, uploadId } = await require_messenger.prepareFileConsentActivityFs({
839
- media: {
840
- buffer: media.buffer,
841
- filename: fileName,
842
- contentType: media.contentType
843
- },
844
- conversationId,
845
- description: messageText || void 0
846
- });
847
- log.debug?.("sending file consent card", {
848
- uploadId,
849
- fileName,
850
- size: media.buffer.length
851
- });
852
- const messageId = await sendProactiveActivity({
853
- ctx,
854
- activity,
855
- errorPrefix: "msteams consent card send"
856
- });
857
- require_messenger.setPendingUploadActivityId(uploadId, messageId);
858
- await require_messenger.setPendingUploadActivityIdFs(uploadId, messageId);
859
- log.info("sent file consent card", {
860
- conversationId,
861
- messageId,
862
- uploadId
863
- });
864
- return createMSTeamsSendResult({
865
- messageId,
866
- conversationId,
867
- kind: "card",
868
- pendingUploadId: uploadId
869
- });
870
- }
871
- if (conversationType === "personal") {
872
- const base64 = media.buffer.toString("base64");
873
- return sendTextWithMedia(ctx, messageText, `data:${media.contentType};base64,${base64}`);
874
- }
875
- if (isImage && !sharePointSiteId) {
876
- const base64 = media.buffer.toString("base64");
877
- return sendTextWithMedia(ctx, messageText, `data:${media.contentType};base64,${base64}`);
878
- }
879
- try {
880
- const siteId = require_messenger.requireMSTeamsSharePointSiteId(sharePointSiteId);
881
- log.debug?.("uploading to SharePoint for native file card", {
882
- fileName,
883
- conversationType,
884
- siteId
885
- });
886
- const uploaded = await require_messenger.uploadAndShareSharePoint({
887
- buffer: media.buffer,
888
- filename: fileName,
889
- contentType: media.contentType,
890
- tokenProvider,
891
- siteId,
892
- chatId: conversationId,
893
- usePerUserSharing: conversationType === "groupChat"
894
- });
895
- log.debug?.("SharePoint upload complete", {
896
- itemId: uploaded.itemId,
897
- shareUrl: uploaded.shareUrl
898
- });
899
- const driveItem = await require_messenger.getDriveItemProperties({
900
- siteId,
901
- itemId: uploaded.itemId,
902
- tokenProvider
903
- });
904
- log.debug?.("driveItem properties retrieved", {
905
- eTag: driveItem.eTag,
906
- webDavUrl: driveItem.webDavUrl
907
- });
908
- const fileCardAttachment = require_messenger.buildTeamsFileInfoCard(driveItem);
909
- const messageId = await sendProactiveActivityRaw({
910
- ctx,
911
- activity: {
912
- type: "message",
913
- text: messageText || void 0,
914
- attachments: [fileCardAttachment]
915
- }
916
- });
917
- log.info("sent native file card", {
918
- conversationId,
919
- messageId,
920
- fileName: driveItem.name
921
- });
922
- return createMSTeamsSendResult({
923
- messageId,
924
- conversationId,
925
- kind: "media"
926
- });
927
- } catch (err) {
928
- const classification = require_channel_setup.classifyMSTeamsSendError(err);
929
- const hint = require_channel_setup.formatMSTeamsSendErrorHint(classification);
930
- const status = classification.statusCode ? ` (HTTP ${classification.statusCode})` : "";
931
- throw new Error(`msteams file send failed${status}: ${require_channel_setup.formatUnknownError(err)}${hint ? ` (${hint})` : ""}`, { cause: err });
932
- }
933
- }
934
- return sendTextWithMedia(ctx, messageText, void 0);
935
- }
936
- /**
937
- * Send a text message with optional base64 media URL.
938
- */
939
- async function sendTextWithMedia(ctx, text, mediaUrl) {
940
- const { app, appId, conversationId, ref, log, tokenProvider, sharePointSiteId, mediaMaxBytes, replyStyle } = ctx;
941
- const messages = text && mediaUrl ? [{ text }, { mediaUrl }] : [{
942
- text: text || void 0,
943
- mediaUrl
944
- }];
945
- let platformMessageIds;
946
- try {
947
- platformMessageIds = await require_messenger.sendMSTeamsMessages({
948
- replyStyle,
949
- app,
950
- appId,
951
- conversationRef: ref,
952
- messages,
953
- retry: {},
954
- onRetry: (event) => {
955
- log.debug?.("retrying send", {
956
- conversationId,
957
- ...event
958
- });
959
- },
960
- tokenProvider,
961
- sharePointSiteId,
962
- mediaMaxBytes,
963
- serviceUrlBoundary: ctx.sdkCloudOptions
964
- });
965
- } catch (err) {
966
- const classification = require_channel_setup.classifyMSTeamsSendError(err);
967
- const hint = require_channel_setup.formatMSTeamsSendErrorHint(classification);
968
- const status = classification.statusCode ? ` (HTTP ${classification.statusCode})` : "";
969
- throw new Error(`msteams send failed${status}: ${require_channel_setup.formatUnknownError(err)}${hint ? ` (${hint})` : ""}`, { cause: err });
970
- }
971
- const messageId = platformMessageIds[0] ?? "unknown";
972
- log.info("sent proactive message", {
973
- conversationId,
974
- messageId
975
- });
976
- return {
977
- messageId,
978
- conversationId,
979
- receipt: createMSTeamsSendReceipt({
980
- conversationId,
981
- platformMessageIds,
982
- kind: mediaUrl ? "media" : "text",
983
- ...text && mediaUrl ? { kinds: ["text", "media"] } : {}
984
- })
985
- };
986
- }
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
992
- })) ?? "unknown";
993
- }
994
- async function sendProactiveActivity({ ctx, activity, errorPrefix }) {
995
- try {
996
- return await sendProactiveActivityRaw({
997
- ctx,
998
- activity
999
- });
1000
- } catch (err) {
1001
- const classification = require_channel_setup.classifyMSTeamsSendError(err);
1002
- const hint = require_channel_setup.formatMSTeamsSendErrorHint(classification);
1003
- const status = classification.statusCode ? ` (HTTP ${classification.statusCode})` : "";
1004
- throw new Error(`${errorPrefix} failed${status}: ${require_channel_setup.formatUnknownError(err)}${hint ? ` (${hint})` : ""}`, { cause: err });
1005
- }
1006
- }
1007
- /**
1008
- * Send a poll (Adaptive Card) to a Teams conversation or user.
1009
- */
1010
- async function sendPollMSTeams(params) {
1011
- const { cfg, to, question, options, maxSelections } = params;
1012
- const ctx = await resolveMSTeamsSendContext({
1013
- cfg,
1014
- to
1015
- });
1016
- const { conversationId, log } = ctx;
1017
- const pollCard = require_polls.buildMSTeamsPollCard({
1018
- question,
1019
- options,
1020
- maxSelections
1021
- });
1022
- log.debug?.("sending poll", {
1023
- conversationId,
1024
- pollId: pollCard.pollId,
1025
- optionCount: pollCard.options.length
1026
- });
1027
- const messageId = await sendProactiveActivity({
1028
- ctx,
1029
- activity: {
1030
- type: "message",
1031
- attachments: [{
1032
- contentType: "application/vnd.microsoft.card.adaptive",
1033
- content: pollCard.card
1034
- }]
1035
- },
1036
- errorPrefix: "msteams poll send"
1037
- });
1038
- log.info("sent poll", {
1039
- conversationId,
1040
- pollId: pollCard.pollId,
1041
- messageId
1042
- });
1043
- return {
1044
- pollId: pollCard.pollId,
1045
- messageId,
1046
- conversationId
1047
- };
1048
- }
1049
- /**
1050
- * Send an arbitrary Adaptive Card to a Teams conversation or user.
1051
- */
1052
- async function sendAdaptiveCardMSTeams(params) {
1053
- const { cfg, to, card } = params;
1054
- const ctx = await resolveMSTeamsSendContext({
1055
- cfg,
1056
- to
1057
- });
1058
- const { conversationId, log } = ctx;
1059
- log.debug?.("sending adaptive card", {
1060
- conversationId,
1061
- cardType: card.type,
1062
- cardVersion: card.version
1063
- });
1064
- const messageId = await sendProactiveActivity({
1065
- ctx,
1066
- activity: {
1067
- type: "message",
1068
- attachments: [{
1069
- contentType: "application/vnd.microsoft.card.adaptive",
1070
- content: card
1071
- }]
1072
- },
1073
- errorPrefix: "msteams card send"
1074
- });
1075
- log.info("sent adaptive card", {
1076
- conversationId,
1077
- messageId
1078
- });
1079
- return {
1080
- messageId,
1081
- conversationId
1082
- };
1083
- }
1084
- /**
1085
- * Edit (update) a previously sent message in a Teams conversation.
1086
- *
1087
- * Uses the Bot Framework REST API for proactive edits outside of the
1088
- * original turn context.
1089
- */
1090
- async function editMessageMSTeams(params) {
1091
- const { cfg, to, activityId, text } = params;
1092
- const { app, conversationId, ref, log, sdkCloudOptions } = await resolveMSTeamsSendContext({
1093
- cfg,
1094
- to
1095
- });
1096
- log.debug?.("editing proactive message", {
1097
- conversationId,
1098
- activityId,
1099
- textLength: text.length
1100
- });
1101
- try {
1102
- await require_messenger.updateMSTeamsActivityWithReference(app, require_messenger.buildConversationReference(ref), activityId, {
1103
- type: "message",
1104
- id: activityId,
1105
- text
1106
- }, { serviceUrlBoundary: sdkCloudOptions });
1107
- } catch (err) {
1108
- const classification = require_channel_setup.classifyMSTeamsSendError(err);
1109
- const hint = require_channel_setup.formatMSTeamsSendErrorHint(classification);
1110
- const status = classification.statusCode ? ` (HTTP ${classification.statusCode})` : "";
1111
- throw new Error(`msteams edit failed${status}: ${require_channel_setup.formatUnknownError(err)}${hint ? ` (${hint})` : ""}`, { cause: err });
1112
- }
1113
- log.info("edited proactive message", {
1114
- conversationId,
1115
- activityId
1116
- });
1117
- return { conversationId };
1118
- }
1119
- /**
1120
- * Delete a previously sent message in a Teams conversation.
1121
- *
1122
- * Uses the Bot Framework REST API for proactive deletes outside of the
1123
- * original turn context.
1124
- */
1125
- async function deleteMessageMSTeams(params) {
1126
- const { cfg, to, activityId } = params;
1127
- const { app, conversationId, ref, log, sdkCloudOptions } = await resolveMSTeamsSendContext({
1128
- cfg,
1129
- to
1130
- });
1131
- log.debug?.("deleting proactive message", {
1132
- conversationId,
1133
- activityId
1134
- });
1135
- try {
1136
- await require_messenger.deleteMSTeamsActivityWithReference(app, require_messenger.buildConversationReference(ref), activityId, { serviceUrlBoundary: sdkCloudOptions });
1137
- } catch (err) {
1138
- const classification = require_channel_setup.classifyMSTeamsSendError(err);
1139
- const hint = require_channel_setup.formatMSTeamsSendErrorHint(classification);
1140
- const status = classification.statusCode ? ` (HTTP ${classification.statusCode})` : "";
1141
- throw new Error(`msteams delete failed${status}: ${require_channel_setup.formatUnknownError(err)}${hint ? ` (${hint})` : ""}`, { cause: err });
1142
- }
1143
- log.info("deleted proactive message", {
1144
- conversationId,
1145
- activityId
1146
- });
1147
- return { conversationId };
1148
- }
1149
- //#endregion
1150
587
  //#region extensions/msteams/src/outbound.ts
1151
588
  const MSTEAMS_TEXT_CHUNK_LIMIT = 4e3;
1152
589
  function resolveMSTeamsEffectiveTextChunkLimit(configuredLimit) {
@@ -1170,14 +607,14 @@ function resolveMSTeamsThreadTarget(to, threadId) {
1170
607
  return `${to};messageid=${normalizedThreadId}`;
1171
608
  }
1172
609
  function resolveMSTeamsTextSend(params) {
1173
- return (0, openclaw_plugin_sdk_channel_outbound.resolveOutboundSendDep)(params.deps, "msteams") ?? ((to, text) => sendMessageMSTeams({
610
+ return (0, openclaw_plugin_sdk_channel_outbound.resolveOutboundSendDep)(params.deps, "msteams") ?? ((to, text) => require_send.sendMessageMSTeams({
1174
611
  cfg: params.cfg,
1175
612
  to,
1176
613
  text
1177
614
  }));
1178
615
  }
1179
616
  function resolveMSTeamsMediaSend(params) {
1180
- return (0, openclaw_plugin_sdk_channel_outbound.resolveOutboundSendDep)(params.deps, "msteams") ?? ((to, text, opts) => sendMessageMSTeams({
617
+ return (0, openclaw_plugin_sdk_channel_outbound.resolveOutboundSendDep)(params.deps, "msteams") ?? ((to, text, opts) => require_send.sendMessageMSTeams({
1181
618
  cfg: params.cfg,
1182
619
  to,
1183
620
  text,
@@ -1219,11 +656,14 @@ const msteamsOutbound = {
1219
656
  sendPayload: async ({ cfg, to, text, mediaUrl, mediaAccess, mediaLocalRoots, mediaReadFile, payload, deps, onDeliveryResult, threadId }) => {
1220
657
  const deliveryTarget = resolveMSTeamsThreadTarget(to, threadId);
1221
658
  const presentationCard = (0, openclaw_plugin_sdk_string_coerce_runtime.asOptionalRecord)(payload.channelData?.msteams)?.presentationCard;
1222
- if (presentationCard && typeof presentationCard === "object" && !Array.isArray(presentationCard)) return (0, openclaw_plugin_sdk_channel_send_result.attachChannelToResult)("msteams", toMSTeamsOutboundResult(await sendAdaptiveCardMSTeams({
1223
- cfg,
1224
- to: deliveryTarget,
1225
- card: presentationCard
1226
- })));
659
+ if (presentationCard && typeof presentationCard === "object" && !Array.isArray(presentationCard)) {
660
+ const result = await require_send.sendAdaptiveCardMSTeams({
661
+ cfg,
662
+ to: deliveryTarget,
663
+ card: presentationCard
664
+ });
665
+ return (0, openclaw_plugin_sdk_channel_send_result.attachChannelToResult)("msteams", toMSTeamsOutboundResult(result));
666
+ }
1227
667
  const mediaUrls = (0, openclaw_plugin_sdk_string_normalization_runtime.normalizeStringEntries)((0, openclaw_plugin_sdk_reply_payload.resolvePayloadMediaUrls)({
1228
668
  ...payload,
1229
669
  mediaUrl: payload.mediaUrl ?? mediaUrl
@@ -1284,7 +724,7 @@ const msteamsOutbound = {
1284
724
  },
1285
725
  sendPoll: async ({ cfg, to, poll, threadId }) => {
1286
726
  const maxSelections = poll.maxSelections ?? 1;
1287
- const result = await sendPollMSTeams({
727
+ const result = await require_send.sendPollMSTeams({
1288
728
  cfg,
1289
729
  to: resolveMSTeamsThreadTarget(to, threadId),
1290
730
  question: poll.question,
@@ -1345,10 +785,11 @@ async function probeMSTeams(cfg) {
1345
785
  })) throw new Error("Failed to acquire bot token");
1346
786
  let graph;
1347
787
  try {
1348
- const accessToken = require_resolve_allowlist.readAccessToken(await require_resolve_allowlist.withMSTeamsRequestDeadline({
788
+ const graphTokenValue = await require_resolve_allowlist.withMSTeamsRequestDeadline({
1349
789
  label: "MS Teams Graph probe token",
1350
790
  work: () => tokenProvider.getAccessToken("https://graph.microsoft.com")
1351
- }));
791
+ });
792
+ const accessToken = require_resolve_allowlist.readAccessToken(graphTokenValue);
1352
793
  const payload = accessToken ? decodeJwtPayload(accessToken) : null;
1353
794
  graph = {
1354
795
  ok: true,
@@ -1400,8 +841,8 @@ async function probeMSTeams(cfg) {
1400
841
  //#region extensions/msteams/src/channel.runtime.ts
1401
842
  const msTeamsChannelRuntime = {
1402
843
  addParticipantMSTeams,
1403
- deleteMessageMSTeams,
1404
- editMessageMSTeams,
844
+ deleteMessageMSTeams: require_send.deleteMessageMSTeams,
845
+ editMessageMSTeams: require_send.editMessageMSTeams,
1405
846
  getChannelInfoMSTeams,
1406
847
  getMemberInfoMSTeams,
1407
848
  getMessageMSTeams,
@@ -1419,8 +860,8 @@ const msTeamsChannelRuntime = {
1419
860
  listMSTeamsDirectoryPeersLive,
1420
861
  msteamsOutbound: { ...msteamsOutbound },
1421
862
  probeMSTeams,
1422
- sendAdaptiveCardMSTeams,
1423
- sendMessageMSTeams
863
+ sendAdaptiveCardMSTeams: require_send.sendAdaptiveCardMSTeams,
864
+ sendMessageMSTeams: require_send.sendMessageMSTeams
1424
865
  };
1425
866
  //#endregion
1426
867
  exports.msTeamsChannelRuntime = msTeamsChannelRuntime;