@openclaw/msteams 2026.5.26 → 2026.5.27

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.
package/dist/api.js CHANGED
@@ -1,3 +1,3 @@
1
- import { i as msteamsSetupAdapter, n as openDelegatedOAuthUrl, r as createMSTeamsSetupWizardBase, t as msteamsSetupWizard } from "./setup-surface-f9pZ7G9O.js";
2
- import { t as msteamsPlugin } from "./channel-DZt_jPWh.js";
1
+ import { i as msteamsSetupAdapter, n as openDelegatedOAuthUrl, r as createMSTeamsSetupWizardBase, t as msteamsSetupWizard } from "./setup-surface-evwYex71.js";
2
+ import { t as msteamsPlugin } from "./channel-c7nnGfMx.js";
3
3
  export { createMSTeamsSetupWizardBase, msteamsPlugin, msteamsSetupAdapter, msteamsSetupWizard, openDelegatedOAuthUrl };
@@ -1,18 +1,17 @@
1
- import { O as resolveNestedAllowlistDecision, S as normalizeChannelSlug, T as resolveChannelEntryMatchWithFallback, _ as isDangerousNameMatchingEnabled, i as buildChannelKeyCandidates, k as resolveToolsBySender, o as buildProbeChannelStatusSummary, r as PAIRING_APPROVED_MESSAGE, s as chunkTextForOutbound, t as DEFAULT_ACCOUNT_ID, u as createDefaultChannelRuntimeState, w as resolveAllowlistMatchSimple } from "./runtime-api-CJC3UvbX.js";
2
- import { h as resolveMSTeamsCredentials } from "./graph-users-CwYemYEo.js";
3
- import { a as looksLikeMSTeamsTargetId, c as parseMSTeamsConversationId, d as resolveMSTeamsUserAllowlist, i as msteamsSetupAdapter, l as parseMSTeamsTeamChannelInput, o as normalizeMSTeamsMessagingTarget, s as normalizeMSTeamsUserInput, t as msteamsSetupWizard, u as resolveMSTeamsChannelAllowlist } from "./setup-surface-f9pZ7G9O.js";
1
+ import { O as resolveNestedAllowlistDecision, S as normalizeChannelSlug, T as resolveChannelEntryMatchWithFallback, _ as isDangerousNameMatchingEnabled, i as buildChannelKeyCandidates, k as resolveToolsBySender, o as buildProbeChannelStatusSummary, r as PAIRING_APPROVED_MESSAGE, s as chunkTextForOutbound, t as DEFAULT_ACCOUNT_ID, u as createDefaultChannelRuntimeState, w as resolveAllowlistMatchSimple } from "./runtime-api-BlvMnDKz.js";
2
+ import { h as resolveMSTeamsCredentials } from "./graph-users-uPAE6-KQ.js";
3
+ import { a as looksLikeMSTeamsTargetId, c as parseMSTeamsConversationId, d as resolveMSTeamsUserAllowlist, i as msteamsSetupAdapter, l as parseMSTeamsTeamChannelInput, o as normalizeMSTeamsMessagingTarget, s as normalizeMSTeamsUserInput, t as msteamsSetupWizard, u as resolveMSTeamsChannelAllowlist } from "./setup-surface-evwYex71.js";
4
4
  import { t as MSTeamsChannelConfigSchema } from "./config-schema-CuksCQKC.js";
5
5
  import { describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
6
6
  import { formatAllowFromLowercase } from "openclaw/plugin-sdk/allow-from";
7
7
  import { createTopLevelChannelConfigAdapter } from "openclaw/plugin-sdk/channel-config-helpers";
8
8
  import { buildChannelOutboundSessionRoute, createChatChannelPlugin, stripChannelTargetPrefix, stripTargetKindPrefix } from "openclaw/plugin-sdk/channel-core";
9
- import { createChannelMessageAdapterFromOutbound } from "openclaw/plugin-sdk/channel-message";
9
+ import { createChannelMessageAdapterFromOutbound, createRuntimeOutboundDelegates } from "openclaw/plugin-sdk/channel-outbound";
10
10
  import { createPairingPrefixStripper } from "openclaw/plugin-sdk/channel-pairing";
11
11
  import { createAllowlistProviderGroupPolicyWarningCollector, createDangerousNameMatchingMutableAllowlistWarningCollector, projectConfigWarningCollector } from "openclaw/plugin-sdk/channel-policy";
12
12
  import { createChannelDirectoryAdapter, createRuntimeDirectoryLiveAdapter, listDirectoryEntriesFromSources } from "openclaw/plugin-sdk/directory-runtime";
13
13
  import { adaptMessagePresentationForChannel, normalizeMessagePresentation } from "openclaw/plugin-sdk/interactive-runtime";
14
14
  import { createLazyRuntimeNamedExport } from "openclaw/plugin-sdk/lazy-runtime";
15
- import { createRuntimeOutboundDelegates } from "openclaw/plugin-sdk/outbound-runtime";
16
15
  import { createComputedAccountStatusAdapter } from "openclaw/plugin-sdk/status-helpers";
17
16
  import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
18
17
  import { Type } from "typebox";
@@ -331,7 +330,7 @@ const collectMSTeamsSecurityWarnings = createAllowlistProviderGroupPolicyWarning
331
330
  resolveGroupPolicy: ({ cfg }) => cfg.channels?.msteams?.groupPolicy,
332
331
  collect: ({ groupPolicy }) => groupPolicy === "open" ? ["- MS Teams groups: groupPolicy=\"open\" allows any member to trigger (mention-gated). Set channels.msteams.groupPolicy=\"allowlist\" + channels.msteams.groupAllowFrom to restrict senders."] : []
333
332
  });
334
- const loadMSTeamsChannelRuntime = createLazyRuntimeNamedExport(() => import("./channel.runtime-BJgDc9SC.js"), "msTeamsChannelRuntime");
333
+ const loadMSTeamsChannelRuntime = createLazyRuntimeNamedExport(() => import("./channel.runtime-Boha-kk1.js"), "msTeamsChannelRuntime");
335
334
  const resolveMSTeamsChannelConfig = (cfg) => ({
336
335
  allowFrom: cfg.channels?.msteams?.allowFrom,
337
336
  defaultTo: cfg.channels?.msteams?.defaultTo
@@ -1117,7 +1116,7 @@ const msteamsPlugin = createChatChannelPlugin({
1117
1116
  })
1118
1117
  }),
1119
1118
  gateway: { startAccount: async (ctx) => {
1120
- const { monitorMSTeamsProvider } = await import("./src-B2Yc1zLS.js");
1119
+ const { monitorMSTeamsProvider } = await import("./src-ui0zJEZI.js");
1121
1120
  const port = ctx.cfg.channels?.msteams?.webhook?.port ?? 3978;
1122
1121
  ctx.setStatus({
1123
1122
  accountId: ctx.accountId,
@@ -1,2 +1,2 @@
1
- import { t as msteamsPlugin } from "./channel-DZt_jPWh.js";
1
+ import { t as msteamsPlugin } from "./channel-c7nnGfMx.js";
2
2
  export { msteamsPlugin };
@@ -1,11 +1,11 @@
1
- import { C as normalizeStringEntries$1, s as chunkTextForOutbound } from "./runtime-api-CJC3UvbX.js";
2
- import { a as fetchGraphJson, c as normalizeQuery, d as postGraphJson, f as resolveGraphToken, i as fetchGraphAbsoluteUrl, l as patchGraphJson, n as deleteGraphRequest, o as listChannelsForTeam, r as escapeOData, s as listTeamsByName, t as searchGraphUsers, u as postGraphBetaJson } from "./graph-users-CwYemYEo.js";
3
- import { n as MSTEAMS_PRESENTATION_CAPABILITIES, r as buildMSTeamsPresentationCard } from "./channel-DZt_jPWh.js";
4
- import { S as createMSTeamsConversationStoreFs, a as sendMessageMSTeams, b as createMSTeamsPollStoreFs, i as sendAdaptiveCardMSTeams, n as deleteMessageMSTeams, o as sendPollMSTeams, r as editMessageMSTeams, t as probeMSTeams } from "./probe-DC3tmy9c.js";
1
+ import { C as normalizeStringEntries$1, s as chunkTextForOutbound } from "./runtime-api-BlvMnDKz.js";
2
+ import { a as fetchGraphJson, c as normalizeQuery, d as postGraphJson, f as resolveGraphToken, i as fetchGraphAbsoluteUrl, l as patchGraphJson, n as deleteGraphRequest, o as listChannelsForTeam, r as escapeOData, s as listTeamsByName, t as searchGraphUsers, u as postGraphBetaJson } from "./graph-users-uPAE6-KQ.js";
3
+ import { n as MSTEAMS_PRESENTATION_CAPABILITIES, r as buildMSTeamsPresentationCard } from "./channel-c7nnGfMx.js";
4
+ import { S as createMSTeamsConversationStoreFs, a as sendMessageMSTeams, b as createMSTeamsPollStoreFs, i as sendAdaptiveCardMSTeams, n as deleteMessageMSTeams, o as sendPollMSTeams, r as editMessageMSTeams, t as probeMSTeams } from "./probe-istgFnuw.js";
5
+ import { resolveOutboundSendDep } from "openclaw/plugin-sdk/channel-outbound";
5
6
  import { normalizeLowercaseStringOrEmpty, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
6
7
  import { resolvePayloadMediaUrls, resolveTextChunksWithFallback, sendPayloadMediaSequence } from "openclaw/plugin-sdk/reply-payload";
7
8
  import { attachChannelToResult, createAttachedChannelResultAdapter } from "openclaw/plugin-sdk/channel-send-result";
8
- import { resolveOutboundSendDep } from "openclaw/plugin-sdk/outbound-send-deps";
9
9
  //#region extensions/msteams/src/directory-live.ts
10
10
  async function listMSTeamsDirectoryPeersLive(params) {
11
11
  const query = normalizeQuery(params.query);
@@ -1,4 +1,4 @@
1
- import { M as getMSTeamsRuntime, h as fetchWithSsrFGuard$1 } from "./runtime-api-CJC3UvbX.js";
1
+ import { M as getMSTeamsRuntime, h as fetchWithSsrFGuard$1 } from "./runtime-api-BlvMnDKz.js";
2
2
  import { n as refreshMSTeamsDelegatedTokens } from "./oauth.token-BNbWziwM.js";
3
3
  import { createRequire } from "node:module";
4
4
  import { isRecord, isRecord as isRecord$1, normalizeLowercaseStringOrEmpty, normalizeOptionalString, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
@@ -403,6 +403,36 @@ async function safeFetchWithPolicy(params) {
403
403
  resolveFn: params.resolveFn
404
404
  });
405
405
  }
406
+ const BOT_FRAMEWORK_SERVICE_URL_HOST_ALLOWLIST = normalizeHostnameSuffixAllowlist([
407
+ "smba.trafficmanager.net",
408
+ "smba.infra.gcc.teams.microsoft.com",
409
+ "smba.infra.gov.teams.microsoft.us",
410
+ "smba.infra.dod.teams.microsoft.us"
411
+ ]);
412
+ const serviceUrlSsrfPolicy = buildHostnameAllowlistPolicyFromSuffixAllowlist(BOT_FRAMEWORK_SERVICE_URL_HOST_ALLOWLIST);
413
+ if (!serviceUrlSsrfPolicy) throw new Error("Microsoft Teams Bot Framework serviceUrl allowlist is empty");
414
+ const BOT_FRAMEWORK_SERVICE_URL_SSRF_POLICY = serviceUrlSsrfPolicy;
415
+ function describeBotFrameworkServiceUrlHost(serviceUrl) {
416
+ try {
417
+ return new URL(serviceUrl.trim()).hostname || "invalid-url";
418
+ } catch {
419
+ return "invalid-url";
420
+ }
421
+ }
422
+ function isAllowedBotFrameworkServiceUrl(serviceUrl) {
423
+ if (typeof serviceUrl !== "string") return false;
424
+ const trimmed = serviceUrl.trim();
425
+ return Boolean(trimmed && isHttpsUrlAllowedByHostnameSuffixAllowlist(trimmed, BOT_FRAMEWORK_SERVICE_URL_HOST_ALLOWLIST));
426
+ }
427
+ function tryNormalizeBotFrameworkServiceUrl(serviceUrl) {
428
+ if (!isAllowedBotFrameworkServiceUrl(serviceUrl)) return;
429
+ return serviceUrl.trim().replace(/\/+$/, "");
430
+ }
431
+ function normalizeBotFrameworkServiceUrl(serviceUrl) {
432
+ const normalized = tryNormalizeBotFrameworkServiceUrl(serviceUrl);
433
+ if (normalized) return normalized;
434
+ throw new Error(`Blocked Microsoft Teams serviceUrl host: ${describeBotFrameworkServiceUrlHost(serviceUrl)}`);
435
+ }
406
436
  //#endregion
407
437
  //#region extensions/msteams/src/errors.ts
408
438
  function formatUnknownError(err) {
@@ -703,7 +733,8 @@ function createBotTokenGetter(app) {
703
733
  };
704
734
  }
705
735
  function createApiClient(sdk, serviceUrl, getToken) {
706
- return new sdk.Client(serviceUrl, {
736
+ const normalizedServiceUrl = normalizeBotFrameworkServiceUrl(serviceUrl);
737
+ return new sdk.Client(normalizedServiceUrl, {
707
738
  token: async () => await getToken() || void 0,
708
739
  headers: { "User-Agent": buildUserAgent() }
709
740
  });
@@ -715,11 +746,13 @@ function normalizeOutboundActivity(textOrActivity) {
715
746
  } : textOrActivity;
716
747
  }
717
748
  function createSendContext(params) {
718
- const apiClient = params.serviceUrl && params.conversationId ? createApiClient(params.sdk, params.serviceUrl, params.getToken) : void 0;
749
+ const normalizedServiceUrl = tryNormalizeBotFrameworkServiceUrl(params.serviceUrl);
750
+ const apiClient = normalizedServiceUrl && params.conversationId ? createApiClient(params.sdk, normalizedServiceUrl, params.getToken) : void 0;
719
751
  return {
720
752
  async sendActivity(textOrActivity) {
721
753
  const msg = normalizeOutboundActivity(textOrActivity);
722
754
  if (params.treatInvokeResponseAsNoop && msg.type === "invokeResponse") return { id: "invokeResponse" };
755
+ if (params.serviceUrl && !normalizedServiceUrl) normalizeBotFrameworkServiceUrl(params.serviceUrl);
723
756
  if (!apiClient || !params.conversationId) return { id: "unknown" };
724
757
  const existingChannelData = msg.channelData && typeof msg.channelData === "object" ? msg.channelData : void 0;
725
758
  const channelData = params.tenantId ? {
@@ -753,7 +786,7 @@ function createSendContext(params) {
753
786
  if (!activityId) throw new Error("updateActivity requires an activity id");
754
787
  if (!params.serviceUrl || !params.conversationId) return { id: "unknown" };
755
788
  return await updateActivityViaRest({
756
- serviceUrl: params.serviceUrl,
789
+ serviceUrl: normalizeBotFrameworkServiceUrl(params.serviceUrl),
757
790
  conversationId: params.conversationId,
758
791
  activityId,
759
792
  activity: nextActivity,
@@ -764,7 +797,7 @@ function createSendContext(params) {
764
797
  if (!activityId) throw new Error("deleteActivity requires an activity id");
765
798
  if (!params.serviceUrl || !params.conversationId) return;
766
799
  await deleteActivityViaRest({
767
- serviceUrl: params.serviceUrl,
800
+ serviceUrl: normalizeBotFrameworkServiceUrl(params.serviceUrl),
768
801
  conversationId: params.conversationId,
769
802
  activityId,
770
803
  token: await params.getToken()
@@ -807,7 +840,7 @@ function createProcessContext(params) {
807
840
  */
808
841
  async function updateActivityViaRest(params) {
809
842
  const { serviceUrl, conversationId, activityId, activity, token } = params;
810
- const url = `${serviceUrl.replace(/\/+$/, "")}/v3/conversations/${encodeURIComponent(conversationId)}/activities/${encodeURIComponent(activityId)}`;
843
+ const url = `${normalizeBotFrameworkServiceUrl(serviceUrl)}/v3/conversations/${encodeURIComponent(conversationId)}/activities/${encodeURIComponent(activityId)}`;
811
844
  const headers = {
812
845
  "Content-Type": "application/json",
813
846
  "User-Agent": buildUserAgent()
@@ -826,7 +859,8 @@ async function updateActivityViaRest(params) {
826
859
  id: activityId
827
860
  })
828
861
  },
829
- auditContext: "msteams-update-activity"
862
+ auditContext: "msteams-update-activity",
863
+ policy: BOT_FRAMEWORK_SERVICE_URL_SSRF_POLICY
830
864
  });
831
865
  try {
832
866
  if (!response.ok) {
@@ -844,7 +878,7 @@ async function updateActivityViaRest(params) {
844
878
  */
845
879
  async function deleteActivityViaRest(params) {
846
880
  const { serviceUrl, conversationId, activityId, token } = params;
847
- const url = `${serviceUrl.replace(/\/+$/, "")}/v3/conversations/${encodeURIComponent(conversationId)}/activities/${encodeURIComponent(activityId)}`;
881
+ const url = `${normalizeBotFrameworkServiceUrl(serviceUrl)}/v3/conversations/${encodeURIComponent(conversationId)}/activities/${encodeURIComponent(activityId)}`;
848
882
  const headers = { "User-Agent": buildUserAgent() };
849
883
  if (token) headers.Authorization = `Bearer ${token}`;
850
884
  const currentFetch = globalThis.fetch;
@@ -855,7 +889,8 @@ async function deleteActivityViaRest(params) {
855
889
  method: "DELETE",
856
890
  headers
857
891
  },
858
- auditContext: "msteams-delete-activity"
892
+ auditContext: "msteams-delete-activity",
893
+ policy: BOT_FRAMEWORK_SERVICE_URL_SSRF_POLICY
859
894
  });
860
895
  try {
861
896
  if (!response.ok) {
@@ -877,8 +912,9 @@ async function deleteActivityViaRest(params) {
877
912
  function createMSTeamsAdapter(app, sdk) {
878
913
  return {
879
914
  async continueConversation(_appId, reference, logic) {
880
- const serviceUrl = reference.serviceUrl;
881
- if (!serviceUrl) throw new Error("Missing serviceUrl in conversation reference");
915
+ const rawServiceUrl = reference.serviceUrl;
916
+ if (!rawServiceUrl) throw new Error("Missing serviceUrl in conversation reference");
917
+ const serviceUrl = normalizeBotFrameworkServiceUrl(rawServiceUrl);
882
918
  const conversationId = reference.conversation?.id;
883
919
  if (!conversationId) throw new Error("Missing conversation.id in conversation reference");
884
920
  const tenantId = reference.tenantId ?? reference.conversation?.tenantId;
@@ -1405,4 +1441,4 @@ async function searchGraphUsers(params) {
1405
1441
  })).value ?? [];
1406
1442
  }
1407
1443
  //#endregion
1408
- export { ATTACHMENT_TAG_RE as A, isLikelyImageAttachment as B, loadMSTeamsSdkWithAuth as C, formatMSTeamsSendErrorHint as D, classifyMSTeamsSendError as E, estimateBase64DecodedBytes as F, resolveAttachmentFetchPolicy as G, isUrlAllowed as H, extractHtmlFromAttachment as I, safeFetchWithPolicy as J, resolveMediaSsrfPolicy as K, extractInlineImageCandidates as L, IMG_SRC_RE as M, applyAuthorizationHeaderForUrl as N, formatUnknownError as O, encodeGraphShareId as P, inferPlaceholder as R, createMSTeamsTokenProvider as S, ensureUserAgentHeader as T, normalizeContentType as U, isRecord$1 as V, readNestedString as W, tryBuildGraphSharesUrlForSharedLink as X, safeHostForUrl as Y, resolveMSTeamsStorePath as _, fetchGraphJson as a, createBotFrameworkJwtValidator as b, normalizeQuery as c, postGraphJson as d, resolveGraphToken as f, saveDelegatedTokens as g, resolveMSTeamsCredentials as h, fetchGraphAbsoluteUrl as i, GRAPH_ROOT as j, isRevokedProxyError as k, patchGraphJson as l, loadDelegatedTokens as m, deleteGraphRequest as n, listChannelsForTeam as o, hasConfiguredMSTeamsCredentials as p, resolveRequestUrl as q, escapeOData as r, listTeamsByName as s, searchGraphUsers as t, postGraphBetaJson as u, normalizeSecretInputString as v, buildUserAgent as w, createMSTeamsAdapter as x, readAccessToken as y, isDownloadableAttachment as z };
1444
+ export { safeHostForUrl as $, describeBotFrameworkServiceUrlHost as A, extractHtmlFromAttachment as B, loadMSTeamsSdkWithAuth as C, formatMSTeamsSendErrorHint as D, classifyMSTeamsSendError as E, GRAPH_ROOT as F, isRecord$1 as G, inferPlaceholder as H, IMG_SRC_RE as I, readNestedString as J, isUrlAllowed as K, applyAuthorizationHeaderForUrl as L, normalizeBotFrameworkServiceUrl as M, tryNormalizeBotFrameworkServiceUrl as N, formatUnknownError as O, ATTACHMENT_TAG_RE as P, safeFetchWithPolicy as Q, encodeGraphShareId as R, createMSTeamsTokenProvider as S, ensureUserAgentHeader as T, isDownloadableAttachment as U, extractInlineImageCandidates as V, isLikelyImageAttachment as W, resolveMediaSsrfPolicy as X, resolveAttachmentFetchPolicy as Y, resolveRequestUrl as Z, resolveMSTeamsStorePath as _, fetchGraphJson as a, createBotFrameworkJwtValidator as b, normalizeQuery as c, postGraphJson as d, tryBuildGraphSharesUrlForSharedLink as et, resolveGraphToken as f, saveDelegatedTokens as g, resolveMSTeamsCredentials as h, fetchGraphAbsoluteUrl as i, isAllowedBotFrameworkServiceUrl as j, isRevokedProxyError as k, patchGraphJson as l, loadDelegatedTokens as m, deleteGraphRequest as n, listChannelsForTeam as o, hasConfiguredMSTeamsCredentials as p, normalizeContentType as q, escapeOData as r, listTeamsByName as s, searchGraphUsers as t, postGraphBetaJson as u, normalizeSecretInputString as v, buildUserAgent as w, createMSTeamsAdapter as x, readAccessToken as y, estimateBase64DecodedBytes as z };
@@ -1,7 +1,7 @@
1
- import { C as normalizeStringEntries$1, E as resolveChannelMediaMaxBytes, M as getMSTeamsRuntime, d as detectMime, g as getFileExtension, m as extractOriginalFilename, p as extensionForMime, y as loadOutboundMediaFromUrl } from "./runtime-api-CJC3UvbX.js";
2
- import { C as loadMSTeamsSdkWithAuth, D as formatMSTeamsSendErrorHint, E as classifyMSTeamsSendError, O as formatUnknownError, S as createMSTeamsTokenProvider, _ as resolveMSTeamsStorePath, h as resolveMSTeamsCredentials, k as isRevokedProxyError, m as loadDelegatedTokens, w as buildUserAgent, x as createMSTeamsAdapter, y as readAccessToken } from "./graph-users-CwYemYEo.js";
3
- import { a as resolveMSTeamsReplyPolicy, o as resolveMSTeamsRouteConfig } from "./channel-DZt_jPWh.js";
4
- import { createMessageReceiptFromOutboundResults } from "openclaw/plugin-sdk/channel-message";
1
+ import { C as normalizeStringEntries$1, E as resolveChannelMediaMaxBytes, M as getMSTeamsRuntime, d as detectMime, g as getFileExtension, m as extractOriginalFilename, p as extensionForMime, y as loadOutboundMediaFromUrl } from "./runtime-api-BlvMnDKz.js";
2
+ import { A as describeBotFrameworkServiceUrlHost, C as loadMSTeamsSdkWithAuth, D as formatMSTeamsSendErrorHint, E as classifyMSTeamsSendError, M as normalizeBotFrameworkServiceUrl, O as formatUnknownError, S as createMSTeamsTokenProvider, _ as resolveMSTeamsStorePath, h as resolveMSTeamsCredentials, j as isAllowedBotFrameworkServiceUrl, k as isRevokedProxyError, m as loadDelegatedTokens, w as buildUserAgent, x as createMSTeamsAdapter, y as readAccessToken } from "./graph-users-uPAE6-KQ.js";
3
+ import { a as resolveMSTeamsReplyPolicy, o as resolveMSTeamsRouteConfig } from "./channel-c7nnGfMx.js";
4
+ import { createMessageReceiptFromOutboundResults } from "openclaw/plugin-sdk/channel-outbound";
5
5
  import { isRecord, normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeStringEntries, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
6
6
  import { withFileLock } from "openclaw/plugin-sdk/file-lock";
7
7
  import { resolveSendableOutboundReplyParts } from "openclaw/plugin-sdk/reply-payload";
@@ -1590,15 +1590,30 @@ async function resolveMSTeamsSendContext(params) {
1590
1590
  });
1591
1591
  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.`);
1592
1592
  const { conversationId, ref } = found;
1593
+ const log = getMSTeamsRuntime().logging.getChildLogger({ name: "msteams:send" });
1594
+ if (ref.serviceUrl && !isAllowedBotFrameworkServiceUrl(ref.serviceUrl)) {
1595
+ try {
1596
+ await store.remove(conversationId);
1597
+ } catch (err) {
1598
+ log.warn?.("failed to remove blocked msteams conversation reference", {
1599
+ conversationId,
1600
+ error: formatUnknownError(err)
1601
+ });
1602
+ }
1603
+ throw new Error(`Stored Microsoft Teams conversation reference has blocked serviceUrl host: ${describeBotFrameworkServiceUrlHost(ref.serviceUrl)}. The bot must receive a new message from this conversation before it can send proactively.`);
1604
+ }
1605
+ const safeRef = ref.serviceUrl ? {
1606
+ ...ref,
1607
+ serviceUrl: normalizeBotFrameworkServiceUrl(ref.serviceUrl)
1608
+ } : ref;
1593
1609
  if (recipient.type === "user") {
1594
- const resolvedType = normalizeLowercaseStringOrEmpty(ref.conversation?.conversationType ?? "");
1610
+ const resolvedType = normalizeLowercaseStringOrEmpty(safeRef.conversation?.conversationType ?? "");
1595
1611
  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.`);
1596
1612
  }
1597
- const log = getMSTeamsRuntime().logging.getChildLogger({ name: "msteams:send" });
1598
1613
  const { sdk, app } = await loadMSTeamsSdkWithAuth(creds);
1599
1614
  const adapter = createMSTeamsAdapter(app, sdk);
1600
1615
  const tokenProvider = createMSTeamsTokenProvider(app);
1601
- const storedConversationType = normalizeLowercaseStringOrEmpty(ref.conversation?.conversationType ?? "");
1616
+ const storedConversationType = normalizeLowercaseStringOrEmpty(safeRef.conversation?.conversationType ?? "");
1602
1617
  let conversationType;
1603
1618
  if (storedConversationType === "personal") conversationType = "personal";
1604
1619
  else if (storedConversationType === "channel") conversationType = "channel";
@@ -1606,7 +1621,7 @@ async function resolveMSTeamsSendContext(params) {
1606
1621
  const replyStyle = resolveMSTeamsProactiveReplyStyle({
1607
1622
  cfg: msteamsCfg,
1608
1623
  conversationId,
1609
- ref,
1624
+ ref: safeRef,
1610
1625
  conversationType
1611
1626
  });
1612
1627
  const sharePointSiteId = msteamsCfg.sharePointSiteId;
@@ -1614,16 +1629,16 @@ async function resolveMSTeamsSendContext(params) {
1614
1629
  cfg: params.cfg,
1615
1630
  resolveChannelLimitMb: ({ cfg }) => cfg.channels?.msteams?.mediaMaxMb
1616
1631
  });
1617
- let graphChatId = ref.graphChatId ?? void 0;
1632
+ let graphChatId = safeRef.graphChatId ?? void 0;
1618
1633
  if (graphChatId === void 0 && sharePointSiteId) try {
1619
1634
  const resolved = await resolveGraphChatId({
1620
1635
  botFrameworkConversationId: conversationId,
1621
- userAadObjectId: ref.user?.aadObjectId,
1636
+ userAadObjectId: safeRef.user?.aadObjectId,
1622
1637
  tokenProvider
1623
1638
  });
1624
1639
  graphChatId = resolved;
1625
1640
  if (resolved) await store.upsert(conversationId, {
1626
- ...ref,
1641
+ ...safeRef,
1627
1642
  graphChatId: resolved
1628
1643
  });
1629
1644
  else log.warn?.("could not resolve Graph chat ID; file uploads may fail for this conversation", { conversationId });
@@ -1637,7 +1652,7 @@ async function resolveMSTeamsSendContext(params) {
1637
1652
  return {
1638
1653
  appId: creds.appId,
1639
1654
  conversationId,
1640
- ref,
1655
+ ref: safeRef,
1641
1656
  adapter,
1642
1657
  log,
1643
1658
  conversationType,
@@ -1,17 +1,15 @@
1
1
  import { mergeAllowlist, resolveAllowlistMatchSimple, summarizeMapping } from "openclaw/plugin-sdk/allow-from";
2
- import { createChannelMessageReplyPipeline } from "openclaw/plugin-sdk/channel-message";
2
+ import { createChannelMessageReplyPipeline, keepHttpServerTaskAlive, logTypingFailure } from "openclaw/plugin-sdk/channel-outbound";
3
3
  import { createChannelPairingController } from "openclaw/plugin-sdk/channel-pairing";
4
4
  import { resolveToolsBySender } from "openclaw/plugin-sdk/channel-policy";
5
5
  import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/account-id";
6
- import { logTypingFailure } from "openclaw/plugin-sdk/channel-logging";
7
6
  import { PAIRING_APPROVED_MESSAGE, buildProbeChannelStatusSummary, createDefaultChannelRuntimeState } from "openclaw/plugin-sdk/channel-status";
8
7
  import { buildChannelKeyCandidates, normalizeChannelSlug, resolveChannelEntryMatchWithFallback, resolveNestedAllowlistDecision } from "openclaw/plugin-sdk/channel-targets";
9
8
  import { isDangerousNameMatchingEnabled } from "openclaw/plugin-sdk/dangerous-name-runtime";
10
9
  import { resolveDefaultGroupPolicy } from "openclaw/plugin-sdk/runtime-group-policy";
11
10
  import { withFileLock as withFileLock$1 } from "openclaw/plugin-sdk/file-lock";
12
- import { keepHttpServerTaskAlive } from "openclaw/plugin-sdk/channel-lifecycle";
13
11
  import { detectMime, extensionForMime, extractOriginalFilename, getFileExtension, resolveChannelMediaMaxBytes } from "openclaw/plugin-sdk/media-runtime";
14
- import { dispatchReplyFromConfigWithSettledDispatcher as dispatchReplyFromConfigWithSettledDispatcher$1 } from "openclaw/plugin-sdk/inbound-reply-dispatch";
12
+ import { dispatchReplyFromConfigWithSettledDispatcher as dispatchReplyFromConfigWithSettledDispatcher$1 } from "openclaw/plugin-sdk/channel-inbound";
15
13
  import { loadOutboundMediaFromUrl } from "openclaw/plugin-sdk/outbound-media";
16
14
  import { buildMediaPayload } from "openclaw/plugin-sdk/reply-payload";
17
15
  import { fetchWithSsrFGuard as fetchWithSsrFGuard$1 } from "openclaw/plugin-sdk/ssrf-runtime";
@@ -1,2 +1,2 @@
1
- import { A as summarizeMapping, C as normalizeStringEntries, D as resolveDefaultGroupPolicy, E as resolveChannelMediaMaxBytes, O as resolveNestedAllowlistDecision, P as setMSTeamsRuntime, S as normalizeChannelSlug, T as resolveChannelEntryMatchWithFallback, _ as isDangerousNameMatchingEnabled, a as buildMediaPayload, b as logTypingFailure, c as createChannelMessageReplyPipeline, d as detectMime, f as dispatchReplyFromConfigWithSettledDispatcher, g as getFileExtension, h as fetchWithSsrFGuard, i as buildChannelKeyCandidates, j as withFileLock, k as resolveToolsBySender, l as createChannelPairingController, m as extractOriginalFilename, n as DEFAULT_WEBHOOK_MAX_BODY_BYTES, o as buildProbeChannelStatusSummary, p as extensionForMime, r as PAIRING_APPROVED_MESSAGE, s as chunkTextForOutbound, t as DEFAULT_ACCOUNT_ID, u as createDefaultChannelRuntimeState, v as keepHttpServerTaskAlive, w as resolveAllowlistMatchSimple, x as mergeAllowlist, y as loadOutboundMediaFromUrl } from "./runtime-api-CJC3UvbX.js";
1
+ import { A as summarizeMapping, C as normalizeStringEntries, D as resolveDefaultGroupPolicy, E as resolveChannelMediaMaxBytes, O as resolveNestedAllowlistDecision, P as setMSTeamsRuntime, S as normalizeChannelSlug, T as resolveChannelEntryMatchWithFallback, _ as isDangerousNameMatchingEnabled, a as buildMediaPayload, b as logTypingFailure, c as createChannelMessageReplyPipeline, d as detectMime, f as dispatchReplyFromConfigWithSettledDispatcher, g as getFileExtension, h as fetchWithSsrFGuard, i as buildChannelKeyCandidates, j as withFileLock, k as resolveToolsBySender, l as createChannelPairingController, m as extractOriginalFilename, n as DEFAULT_WEBHOOK_MAX_BODY_BYTES, o as buildProbeChannelStatusSummary, p as extensionForMime, r as PAIRING_APPROVED_MESSAGE, s as chunkTextForOutbound, t as DEFAULT_ACCOUNT_ID, u as createDefaultChannelRuntimeState, v as keepHttpServerTaskAlive, w as resolveAllowlistMatchSimple, x as mergeAllowlist, y as loadOutboundMediaFromUrl } from "./runtime-api-BlvMnDKz.js";
2
2
  export { DEFAULT_ACCOUNT_ID, DEFAULT_WEBHOOK_MAX_BODY_BYTES, PAIRING_APPROVED_MESSAGE, buildChannelKeyCandidates, buildMediaPayload, buildProbeChannelStatusSummary, chunkTextForOutbound, createChannelMessageReplyPipeline, createChannelPairingController, createDefaultChannelRuntimeState, detectMime, dispatchReplyFromConfigWithSettledDispatcher, extensionForMime, extractOriginalFilename, fetchWithSsrFGuard, getFileExtension, isDangerousNameMatchingEnabled, keepHttpServerTaskAlive, loadOutboundMediaFromUrl, logTypingFailure, mergeAllowlist, normalizeChannelSlug, normalizeStringEntries, resolveAllowlistMatchSimple, resolveChannelEntryMatchWithFallback, resolveChannelMediaMaxBytes, resolveDefaultGroupPolicy, resolveNestedAllowlistDecision, resolveToolsBySender, setMSTeamsRuntime, summarizeMapping, withFileLock };
@@ -1,5 +1,5 @@
1
- import { h as resolveMSTeamsCredentials } from "./graph-users-CwYemYEo.js";
2
- import { i as msteamsSetupAdapter, t as msteamsSetupWizard } from "./setup-surface-f9pZ7G9O.js";
1
+ import { h as resolveMSTeamsCredentials } from "./graph-users-uPAE6-KQ.js";
2
+ import { i as msteamsSetupAdapter, t as msteamsSetupWizard } from "./setup-surface-evwYex71.js";
3
3
  import { t as MSTeamsChannelConfigSchema } from "./config-schema-CuksCQKC.js";
4
4
  import { describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
5
5
  import { formatAllowFromLowercase } from "openclaw/plugin-sdk/allow-from";
@@ -1,4 +1,4 @@
1
- import { O as formatUnknownError, c as normalizeQuery, f as resolveGraphToken, g as saveDelegatedTokens, h as resolveMSTeamsCredentials, o as listChannelsForTeam, p as hasConfiguredMSTeamsCredentials, s as listTeamsByName, t as searchGraphUsers, v as normalizeSecretInputString } from "./graph-users-CwYemYEo.js";
1
+ import { O as formatUnknownError, c as normalizeQuery, f as resolveGraphToken, g as saveDelegatedTokens, h as resolveMSTeamsCredentials, o as listChannelsForTeam, p as hasConfiguredMSTeamsCredentials, s as listTeamsByName, t as searchGraphUsers, v as normalizeSecretInputString } from "./graph-users-uPAE6-KQ.js";
2
2
  import { mapAllowlistResolutionInputs } from "openclaw/plugin-sdk/allow-from";
3
3
  import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString } from "openclaw/plugin-sdk/string-coerce-runtime";
4
4
  import { DEFAULT_ACCOUNT_ID, createSetupTranslator, createStandardChannelSetupStatus, createTopLevelChannelAllowFromSetter, createTopLevelChannelDmPolicy, createTopLevelChannelGroupPolicySetter, mergeAllowFromEntries, splitSetupEntries } from "openclaw/plugin-sdk/setup";
@@ -1,14 +1,13 @@
1
- import { A as summarizeMapping, D as resolveDefaultGroupPolicy, E as resolveChannelMediaMaxBytes, M as getMSTeamsRuntime, N as getOptionalMSTeamsRuntime, _ as isDangerousNameMatchingEnabled, a as buildMediaPayload, b as logTypingFailure, c as createChannelMessageReplyPipeline, f as dispatchReplyFromConfigWithSettledDispatcher$1, l as createChannelPairingController, n as DEFAULT_WEBHOOK_MAX_BODY_BYTES, t as DEFAULT_ACCOUNT_ID, v as keepHttpServerTaskAlive, x as mergeAllowlist } from "./runtime-api-CJC3UvbX.js";
2
- import { A as ATTACHMENT_TAG_RE, B as isLikelyImageAttachment, C as loadMSTeamsSdkWithAuth, D as formatMSTeamsSendErrorHint, E as classifyMSTeamsSendError, F as estimateBase64DecodedBytes, G as resolveAttachmentFetchPolicy, H as isUrlAllowed, I as extractHtmlFromAttachment, J as safeFetchWithPolicy, K as resolveMediaSsrfPolicy, L as extractInlineImageCandidates, M as IMG_SRC_RE, N as applyAuthorizationHeaderForUrl, O as formatUnknownError, P as encodeGraphShareId, R as inferPlaceholder, S as createMSTeamsTokenProvider, T as ensureUserAgentHeader, U as normalizeContentType, V as isRecord$1, W as readNestedString, X as tryBuildGraphSharesUrlForSharedLink, Y as safeHostForUrl, _ as resolveMSTeamsStorePath, a as fetchGraphJson, b as createBotFrameworkJwtValidator, h as resolveMSTeamsCredentials, j as GRAPH_ROOT, q as resolveRequestUrl, w as buildUserAgent, x as createMSTeamsAdapter, z as isDownloadableAttachment } from "./graph-users-CwYemYEo.js";
3
- import { d as resolveMSTeamsUserAllowlist, u as resolveMSTeamsChannelAllowlist } from "./setup-surface-f9pZ7G9O.js";
4
- import { a as resolveMSTeamsReplyPolicy, i as resolveMSTeamsAllowlistMatch, o as resolveMSTeamsRouteConfig } from "./channel-DZt_jPWh.js";
5
- import { C as readJsonFile, S as createMSTeamsConversationStoreFs, T as writeJsonFile, _ as buildFileInfoCard, b as createMSTeamsPollStoreFs, c as renderReplyPayloadsToMessages, d as withRevokedProxyFallback, f as resolveGraphChatId, g as removePendingUploadFs, h as getPendingUploadFs, l as sendMSTeamsMessages, m as removePendingUpload, p as getPendingUpload, s as buildConversationReference, u as AI_GENERATED_ENTITY, v as parseFileConsentInvoke, w as withFileLock, x as extractMSTeamsPollVote, y as uploadToConsentUrl } from "./probe-DC3tmy9c.js";
1
+ import { A as summarizeMapping, D as resolveDefaultGroupPolicy, E as resolveChannelMediaMaxBytes, M as getMSTeamsRuntime, N as getOptionalMSTeamsRuntime, _ as isDangerousNameMatchingEnabled, a as buildMediaPayload, b as logTypingFailure, c as createChannelMessageReplyPipeline, f as dispatchReplyFromConfigWithSettledDispatcher$1, l as createChannelPairingController, n as DEFAULT_WEBHOOK_MAX_BODY_BYTES, t as DEFAULT_ACCOUNT_ID, v as keepHttpServerTaskAlive, x as mergeAllowlist } from "./runtime-api-BlvMnDKz.js";
2
+ import { $ as safeHostForUrl, B as extractHtmlFromAttachment, C as loadMSTeamsSdkWithAuth, D as formatMSTeamsSendErrorHint, E as classifyMSTeamsSendError, F as GRAPH_ROOT, G as isRecord$1, H as inferPlaceholder, I as IMG_SRC_RE, J as readNestedString, K as isUrlAllowed, L as applyAuthorizationHeaderForUrl, N as tryNormalizeBotFrameworkServiceUrl, O as formatUnknownError, P as ATTACHMENT_TAG_RE, Q as safeFetchWithPolicy, R as encodeGraphShareId, S as createMSTeamsTokenProvider, T as ensureUserAgentHeader, U as isDownloadableAttachment, V as extractInlineImageCandidates, W as isLikelyImageAttachment, X as resolveMediaSsrfPolicy, Y as resolveAttachmentFetchPolicy, Z as resolveRequestUrl, _ as resolveMSTeamsStorePath, a as fetchGraphJson, b as createBotFrameworkJwtValidator, et as tryBuildGraphSharesUrlForSharedLink, h as resolveMSTeamsCredentials, q as normalizeContentType, w as buildUserAgent, x as createMSTeamsAdapter, z as estimateBase64DecodedBytes } from "./graph-users-uPAE6-KQ.js";
3
+ import { d as resolveMSTeamsUserAllowlist, u as resolveMSTeamsChannelAllowlist } from "./setup-surface-evwYex71.js";
4
+ import { a as resolveMSTeamsReplyPolicy, i as resolveMSTeamsAllowlistMatch, o as resolveMSTeamsRouteConfig } from "./channel-c7nnGfMx.js";
5
+ import { C as readJsonFile, S as createMSTeamsConversationStoreFs, T as writeJsonFile, _ as buildFileInfoCard, b as createMSTeamsPollStoreFs, c as renderReplyPayloadsToMessages, d as withRevokedProxyFallback, f as resolveGraphChatId, g as removePendingUploadFs, h as getPendingUploadFs, l as sendMSTeamsMessages, m as removePendingUpload, p as getPendingUpload, s as buildConversationReference, u as AI_GENERATED_ENTITY, v as parseFileConsentInvoke, w as withFileLock, x as extractMSTeamsPollVote, y as uploadToConsentUrl } from "./probe-istgFnuw.js";
6
6
  import { formatAllowlistMatchMeta } from "openclaw/plugin-sdk/allow-from";
7
- import { createLiveMessageState, createPreviewMessageReceipt, defineFinalizableLivePreviewAdapter, deliverWithFinalizableLivePreviewAdapter, markLiveMessageFinalized } from "openclaw/plugin-sdk/channel-message";
7
+ import { buildChannelProgressDraftLine, buildChannelProgressDraftLineForEntry, createChannelProgressDraftGate, createDraftStreamLoop, createLiveMessageState, createPreviewMessageReceipt, defineFinalizableLivePreviewAdapter, deliverWithFinalizableLivePreviewAdapter, formatChannelProgressDraftText, isChannelProgressDraftWorkToolName, markLiveMessageFinalized, mergeChannelProgressDraftLine, normalizeChannelProgressDraftLineIdentity, resolveChannelPreviewStreamMode, resolveChannelProgressDraftMaxLines, resolveChannelStreamingBlockEnabled, resolveChannelStreamingPreviewToolProgress } from "openclaw/plugin-sdk/channel-outbound";
8
8
  import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, readStringValue, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
9
- import { createDraftStreamLoop } from "openclaw/plugin-sdk/channel-lifecycle";
10
9
  import { saveResponseMedia } from "openclaw/plugin-sdk/media-runtime";
11
- import { dispatchReplyFromConfigWithSettledDispatcher, hasFinalInboundReplyDispatch, resolveInboundReplyDispatchCounts } from "openclaw/plugin-sdk/inbound-reply-dispatch";
10
+ import { buildChannelInboundEventContext, dispatchReplyFromConfigWithSettledDispatcher, hasFinalInboundReplyDispatch, logInboundDrop, resolveInboundMentionDecision, resolveInboundReplyDispatchCounts, resolveInboundSessionEnvelopeContext } from "openclaw/plugin-sdk/channel-inbound";
12
11
  import { fetchWithSsrFGuard } from "openclaw/plugin-sdk/ssrf-runtime";
13
12
  import path from "node:path";
14
13
  import { appendRegularFile } from "openclaw/plugin-sdk/security-runtime";
@@ -16,10 +15,8 @@ import { writeJsonFileAtomically } from "openclaw/plugin-sdk/json-store";
16
15
  import { resolveThreadSessionKeys } from "openclaw/plugin-sdk/routing";
17
16
  import fs from "node:fs/promises";
18
17
  import { channelIngressRoutes, resolveStableChannelMessageIngress } from "openclaw/plugin-sdk/channel-ingress-runtime";
19
- import { logInboundDrop, resolveInboundMentionDecision, resolveInboundSessionEnvelopeContext } from "openclaw/plugin-sdk/channel-inbound";
20
- import { filterSupplementalContextItems, resolveChannelContextVisibilityMode, shouldIncludeSupplementalContext } from "openclaw/plugin-sdk/context-visibility-runtime";
18
+ import { filterSupplementalContextItems, resolveChannelContextVisibilityMode } from "openclaw/plugin-sdk/context-visibility-runtime";
21
19
  import { DEFAULT_GROUP_HISTORY_LIMIT, createChannelHistoryWindow } from "openclaw/plugin-sdk/reply-history";
22
- import { buildChannelProgressDraftLine, buildChannelProgressDraftLineForEntry, createChannelProgressDraftGate, formatChannelProgressDraftText, isChannelProgressDraftWorkToolName, mergeChannelProgressDraftLine, normalizeChannelProgressDraftLineIdentity, resolveChannelPreviewStreamMode, resolveChannelProgressDraftMaxLines, resolveChannelStreamingBlockEnabled, resolveChannelStreamingPreviewToolProgress } from "openclaw/plugin-sdk/channel-streaming";
23
20
  //#region extensions/msteams/src/feedback-reflection-prompt.ts
24
21
  /** Max chars of the thumbed-down response to include in the reflection prompt. */
25
22
  const MAX_RESPONSE_CHARS = 500;
@@ -2519,6 +2516,7 @@ function buildStoredConversationReference(params) {
2519
2516
  const clientInfo = activity.entities?.find((e) => e.type === "clientInfo");
2520
2517
  const tenantId = activity.channelData?.tenant?.id ?? conversation?.tenantId;
2521
2518
  const aadObjectId = from?.aadObjectId;
2519
+ const serviceUrl = tryNormalizeBotFrameworkServiceUrl(activity.serviceUrl);
2522
2520
  return {
2523
2521
  activityId: activity.id,
2524
2522
  user: from ? {
@@ -2540,7 +2538,7 @@ function buildStoredConversationReference(params) {
2540
2538
  ...aadObjectId ? { aadObjectId } : {},
2541
2539
  teamId,
2542
2540
  channelId: activity.channelId,
2543
- serviceUrl: activity.serviceUrl,
2541
+ ...serviceUrl ? { serviceUrl } : {},
2544
2542
  locale: activity.locale,
2545
2543
  ...clientInfo?.timezone ? { timezone: clientInfo.timezone } : {},
2546
2544
  ...threadId ? { threadId } : {}
@@ -2948,44 +2946,62 @@ function createMSTeamsMessageHandler(deps) {
2948
2946
  senderName: quoteSenderName,
2949
2947
  allowNameMatching
2950
2948
  }).allowed : true;
2951
- const includeQuoteContext = quoteInfo && shouldIncludeSupplementalContext({
2952
- mode: contextVisibilityMode,
2953
- kind: "quote",
2954
- senderAllowed: quoteSenderAllowed
2955
- });
2956
2949
  const bodyForAgent = threadContext ? `[Thread history]\n${threadContext}\n[/Thread history]\n\n${rawBody}` : rawBody;
2957
2950
  const nativeChannelId = isChannel && teamId ? `${teamId}/${conversationId}` : void 0;
2958
- const ctxPayload = core.channel.reply.finalizeInboundContext({
2959
- Body: combinedBody,
2960
- BodyForAgent: bodyForAgent,
2961
- InboundHistory: inboundHistory,
2962
- RawBody: rawBody,
2963
- CommandBody: commandBody,
2964
- BodyForCommands: commandBody,
2965
- From: teamsFrom,
2966
- To: teamsTo,
2967
- SessionKey: route.sessionKey,
2968
- AccountId: route.accountId,
2969
- ChatType: isDirectMessage ? "direct" : isChannel ? "channel" : "group",
2970
- ConversationLabel: envelopeFrom,
2971
- GroupSubject: !isDirectMessage ? conversationType : void 0,
2972
- GroupSpace: teamId,
2973
- SenderName: senderName,
2974
- SenderId: senderId,
2975
- Provider: "msteams",
2976
- Surface: "msteams",
2977
- MessageSid: activity.id,
2978
- Timestamp: timestamp?.getTime() ?? Date.now(),
2979
- WasMentioned: isDirectMessage || mentionDecision.effectiveWasMentioned,
2980
- CommandAuthorized: commandAuthorized,
2981
- OriginatingChannel: "msteams",
2982
- OriginatingTo: teamsTo,
2983
- NativeChannelId: nativeChannelId,
2984
- ReplyToId: activity.replyToId ?? void 0,
2985
- ReplyToBody: includeQuoteContext ? quoteInfo?.body : void 0,
2986
- ReplyToSender: includeQuoteContext ? quoteInfo?.sender : void 0,
2987
- ReplyToIsQuote: quoteInfo ? true : void 0,
2988
- ...mediaPayload
2951
+ const ctxPayload = buildChannelInboundEventContext({
2952
+ channel: "msteams",
2953
+ finalize: core.channel.reply.finalizeInboundContext,
2954
+ contextVisibility: contextVisibilityMode,
2955
+ supplemental: { quote: quoteInfo ? {
2956
+ id: activity.replyToId ?? void 0,
2957
+ body: quoteInfo.body,
2958
+ sender: quoteInfo.sender,
2959
+ senderAllowed: quoteSenderAllowed,
2960
+ isQuote: true
2961
+ } : void 0 },
2962
+ messageId: activity.id,
2963
+ timestamp: timestamp?.getTime() ?? Date.now(),
2964
+ from: teamsFrom,
2965
+ sender: {
2966
+ id: senderId,
2967
+ name: senderName
2968
+ },
2969
+ conversation: {
2970
+ kind: isDirectMessage ? "direct" : isChannel ? "channel" : "group",
2971
+ id: conversationId,
2972
+ label: envelopeFrom,
2973
+ spaceId: teamId,
2974
+ nativeChannelId
2975
+ },
2976
+ route: {
2977
+ agentId: route.agentId,
2978
+ accountId: route.accountId,
2979
+ routeSessionKey: route.sessionKey
2980
+ },
2981
+ reply: {
2982
+ to: teamsTo,
2983
+ replyToId: activity.replyToId ?? void 0,
2984
+ nativeChannelId
2985
+ },
2986
+ message: {
2987
+ body: combinedBody,
2988
+ bodyForAgent,
2989
+ inboundHistory,
2990
+ rawBody,
2991
+ commandBody
2992
+ },
2993
+ access: {
2994
+ mentions: {
2995
+ canDetectMention: !isDirectMessage,
2996
+ wasMentioned: isDirectMessage || mentionDecision.effectiveWasMentioned
2997
+ },
2998
+ commands: { authorized: commandAuthorized }
2999
+ },
3000
+ extra: {
3001
+ GroupSubject: !isDirectMessage ? conversationType : void 0,
3002
+ ReplyToIsQuote: quoteInfo ? true : void 0,
3003
+ ...mediaPayload
3004
+ }
2989
3005
  });
2990
3006
  logVerboseMessage(`msteams inbound: from=${ctxPayload.From} preview="${preview}"`);
2991
3007
  const sharePointSiteId = msteamsCfg?.sharePointSiteId;
@@ -3015,7 +3031,7 @@ function createMSTeamsMessageHandler(deps) {
3015
3031
  } } } : void 0;
3016
3032
  log.info("dispatching to agent", { sessionKey: route.sessionKey });
3017
3033
  try {
3018
- const turnResult = await core.channel.turn.run({
3034
+ const turnResult = await core.channel.inbound.run({
3019
3035
  channel: "msteams",
3020
3036
  accountId: route.accountId,
3021
3037
  raw: context,
@@ -3600,6 +3616,7 @@ async function handleFeedbackInvoke(context, deps) {
3600
3616
  rejectSymlinkParents: true
3601
3617
  }).catch(() => {});
3602
3618
  } catch {}
3619
+ const serviceUrl = tryNormalizeBotFrameworkServiceUrl(activity.serviceUrl);
3603
3620
  const conversationRef = {
3604
3621
  activityId: activity.id,
3605
3622
  user: {
@@ -3621,7 +3638,7 @@ async function handleFeedbackInvoke(context, deps) {
3621
3638
  tenantId: activity.conversation?.tenantId
3622
3639
  },
3623
3640
  channelId: activity.channelId ?? "msteams",
3624
- serviceUrl: activity.serviceUrl,
3641
+ ...serviceUrl ? { serviceUrl } : {},
3625
3642
  locale: activity.locale
3626
3643
  };
3627
3644
  if (isNegative && msteamsCfg?.feedbackReflection !== false) runFeedbackReflection({
package/dist/test-api.js CHANGED
@@ -1,2 +1,2 @@
1
- import { t as msteamsPlugin } from "./channel-DZt_jPWh.js";
1
+ import { t as msteamsPlugin } from "./channel-c7nnGfMx.js";
2
2
  export { msteamsPlugin };
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@openclaw/msteams",
3
- "version": "2026.5.26",
3
+ "version": "2026.5.27",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@openclaw/msteams",
9
- "version": "2026.5.26",
9
+ "version": "2026.5.27",
10
10
  "dependencies": {
11
11
  "@azure/identity": "4.13.1",
12
12
  "@microsoft/teams.api": "2.0.11",
@@ -17,7 +17,7 @@
17
17
  "typebox": "1.1.38"
18
18
  },
19
19
  "peerDependencies": {
20
- "openclaw": ">=2026.5.26"
20
+ "openclaw": ">=2026.5.27"
21
21
  },
22
22
  "peerDependenciesMeta": {
23
23
  "openclaw": {
@@ -1,5 +1,7 @@
1
1
  {
2
2
  "id": "msteams",
3
+ "name": "Microsoft Teams",
4
+ "description": "OpenClaw Microsoft Teams channel plugin for bot conversations.",
3
5
  "activation": {
4
6
  "onStartup": false
5
7
  },
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@openclaw/msteams",
3
- "version": "2026.5.26",
4
- "description": "OpenClaw Microsoft Teams channel plugin",
3
+ "version": "2026.5.27",
4
+ "description": "OpenClaw Microsoft Teams channel plugin for bot conversations.",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/openclaw/openclaw"
@@ -17,7 +17,7 @@
17
17
  "typebox": "1.1.38"
18
18
  },
19
19
  "peerDependencies": {
20
- "openclaw": ">=2026.5.26"
20
+ "openclaw": ">=2026.5.27"
21
21
  },
22
22
  "peerDependenciesMeta": {
23
23
  "openclaw": {
@@ -53,10 +53,10 @@
53
53
  "minHostVersion": ">=2026.4.10"
54
54
  },
55
55
  "compat": {
56
- "pluginApi": ">=2026.5.26"
56
+ "pluginApi": ">=2026.5.27"
57
57
  },
58
58
  "build": {
59
- "openclawVersion": "2026.5.26"
59
+ "openclawVersion": "2026.5.27"
60
60
  },
61
61
  "release": {
62
62
  "publishToClawHub": true,