@openclaw/msteams 2026.8.1-beta.2 → 2026.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,132 +1,28 @@
1
1
  const require_rolldown_runtime = require("./rolldown-runtime-D6vf50IK.cjs");
2
2
  const require_runtime = require("./runtime-gZTAuFux.cjs");
3
3
  require("./runtime-api.cjs");
4
- const require_resolve_allowlist = require("./resolve-allowlist-C6YcNC9a.cjs");
5
- const require_setup_surface = require("./setup-surface-DAhGL2h8.cjs");
4
+ const require_resolve_allowlist = require("./resolve-allowlist-CWbvAW4v.cjs");
5
+ const require_channel_setup = require("./channel.setup-CKb8aKCV.cjs");
6
6
  const require_polls = require("./polls-DvuJvaDG.cjs");
7
7
  let openclaw_plugin_sdk_lazy_runtime = require("openclaw/plugin-sdk/lazy-runtime");
8
8
  let openclaw_plugin_sdk_string_coerce_runtime = require("openclaw/plugin-sdk/string-coerce-runtime");
9
+ let openclaw_plugin_sdk_provider_http = require("openclaw/plugin-sdk/provider-http");
9
10
  let openclaw_plugin_sdk_reply_payload = require("openclaw/plugin-sdk/reply-payload");
10
11
  let openclaw_plugin_sdk_text_chunking = require("openclaw/plugin-sdk/text-chunking");
11
- let openclaw_plugin_sdk_html_entity_runtime = require("openclaw/plugin-sdk/html-entity-runtime");
12
- let openclaw_plugin_sdk_provider_http = require("openclaw/plugin-sdk/provider-http");
13
12
  let node_dns_promises = require("node:dns/promises");
14
13
  let openclaw_plugin_sdk_ssrf_policy = require("openclaw/plugin-sdk/ssrf-policy");
15
14
  let openclaw_plugin_sdk_text_utility_runtime = require("openclaw/plugin-sdk/text-utility-runtime");
16
- let openclaw_plugin_sdk_error_runtime = require("openclaw/plugin-sdk/error-runtime");
15
+ let openclaw_plugin_sdk_retry_runtime = require("openclaw/plugin-sdk/retry-runtime");
17
16
  let node_crypto = require("node:crypto");
18
17
  node_crypto = require_rolldown_runtime.__toESM(node_crypto, 1);
19
18
  let node_path = require("node:path");
20
19
  node_path = require_rolldown_runtime.__toESM(node_path, 1);
20
+ let openclaw_plugin_sdk_runtime_env = require("openclaw/plugin-sdk/runtime-env");
21
21
  let openclaw_plugin_sdk_global_singleton = require("openclaw/plugin-sdk/global-singleton");
22
+ let openclaw_plugin_sdk_error_runtime = require("openclaw/plugin-sdk/error-runtime");
22
23
  let openclaw_plugin_sdk_reply_chunking = require("openclaw/plugin-sdk/reply-chunking");
23
24
  let openclaw_plugin_sdk_web_media = require("openclaw/plugin-sdk/web-media");
24
25
  let openclaw_plugin_sdk_media_runtime = require("openclaw/plugin-sdk/media-runtime");
25
- //#region extensions/msteams/src/graph-thread.ts
26
- /**
27
- * Strip HTML tags from Teams message content, preserving @mention display names.
28
- * Teams wraps mentions in <at>Name</at> tags.
29
- */
30
- function stripHtmlFromTeamsMessage(html) {
31
- let text = html.replace(/<at[^>]*>(.*?)<\/at>/gi, "@$1");
32
- text = text.replace(/<[^>]*>/g, " ");
33
- text = (0, openclaw_plugin_sdk_html_entity_runtime.decodeHtmlEntities)(text).replaceAll("\xA0", " ");
34
- return text.replace(/\s+/g, " ").trim();
35
- }
36
- /**
37
- * Fetch a single channel message (the parent/root of a thread).
38
- * Returns undefined on error so callers can degrade gracefully.
39
- */
40
- async function fetchChannelMessage(token, groupId, channelId, messageId, deadline) {
41
- const path = `/teams/${encodeURIComponent(groupId)}/channels/${encodeURIComponent(channelId)}/messages/${encodeURIComponent(messageId)}?$select=id,from,body,createdDateTime`;
42
- try {
43
- return await require_resolve_allowlist.fetchGraphJson({
44
- token,
45
- path,
46
- ...deadline ? { deadline } : {}
47
- });
48
- } catch {
49
- return;
50
- }
51
- }
52
- /**
53
- * Fetch a single chat message's full text via Graph and return plain text.
54
- *
55
- * Used to recover the complete quoted message for Teams quote replies: the
56
- * inbound blockquote only carries a Teams-truncated `preview` snippet. The
57
- * app-only `GET /chats/{chatId}/messages/{messageId}` endpoint IS permitted
58
- * with the `Chat.Read.All` application permission.
59
- *
60
- * Returns undefined on any failure so callers degrade to the truncated preview.
61
- */
62
- async function fetchChatMessageText(token, chatId, messageId, deadline) {
63
- const path = `/chats/${encodeURIComponent(chatId)}/messages/${encodeURIComponent(messageId)}`;
64
- try {
65
- const msg = await require_resolve_allowlist.fetchGraphJson({
66
- token,
67
- path,
68
- ...deadline ? { deadline } : {}
69
- });
70
- const raw = msg.body?.content ?? "";
71
- return (msg.body?.contentType === "html" ? stripHtmlFromTeamsMessage(raw) : raw.trim()) || void 0;
72
- } catch {
73
- return;
74
- }
75
- }
76
- /**
77
- * Fetch thread replies for a channel message, ordered chronologically.
78
- *
79
- * **Limitation:** The Graph API replies endpoint (`/messages/{id}/replies`) does not
80
- * support `$orderby`, so results are always returned in ascending (oldest-first) order.
81
- * Combined with the `$top` cap of 50, this means only the **oldest 50 replies** are
82
- * returned for long threads — newer replies are silently omitted. There is currently no
83
- * Graph API workaround for this; pagination via `@odata.nextLink` can retrieve more
84
- * replies but still in ascending order only.
85
- */
86
- async function fetchThreadReplies(token, groupId, channelId, messageId, limit = 50, deadline) {
87
- return (await require_resolve_allowlist.fetchGraphJson({
88
- token,
89
- path: `/teams/${encodeURIComponent(groupId)}/channels/${encodeURIComponent(channelId)}/messages/${encodeURIComponent(messageId)}/replies?$top=${Math.min(Math.max(limit, 1), 50)}&$select=id,from,body,createdDateTime`,
90
- ...deadline ? { deadline } : {}
91
- })).value ?? [];
92
- }
93
- /**
94
- * Format thread messages into a context string for the agent.
95
- * Skips the current message (by id) and blank messages.
96
- */
97
- function formatThreadContext(messages, currentMessageId) {
98
- const lines = [];
99
- for (const msg of messages) {
100
- if (msg.id && msg.id === currentMessageId) continue;
101
- const sender = msg.from?.user?.displayName ?? msg.from?.application?.displayName ?? "unknown";
102
- const contentType = msg.body?.contentType ?? "text";
103
- const rawContent = msg.body?.content ?? "";
104
- const content = contentType === "html" ? stripHtmlFromTeamsMessage(rawContent) : rawContent.trim();
105
- if (!content) continue;
106
- lines.push(`${sender}: ${content}`);
107
- }
108
- return lines.join("\n");
109
- }
110
- //#endregion
111
- //#region extensions/msteams/src/reaction-types.ts
112
- const TEAMS_REACTION_EMOJI = {
113
- like: "👍",
114
- heart: "❤️",
115
- laugh: "😆",
116
- surprised: "😮",
117
- sad: "😢",
118
- angry: "😡"
119
- };
120
- const TEAMS_REACTION_TYPES = Object.keys(TEAMS_REACTION_EMOJI);
121
- function getMSTeamsReactionEmoji(raw) {
122
- return TEAMS_REACTION_EMOJI[raw.trim().toLowerCase()];
123
- }
124
- function resolveMSTeamsReactionEmoji(raw) {
125
- const normalized = raw.trim();
126
- if (!normalized) throw new Error(`Reaction type is required. Common types: ${TEAMS_REACTION_TYPES.join(", ")}`);
127
- return getMSTeamsReactionEmoji(normalized) ?? normalized;
128
- }
129
- //#endregion
130
26
  //#region extensions/msteams/src/file-consent.ts
131
27
  /**
132
28
  * FileConsentCard utilities for MS Teams large file uploads (>4MB) in personal chats.
@@ -1323,6 +1219,15 @@ function extractMessageId(response) {
1323
1219
  return id;
1324
1220
  }
1325
1221
  //#endregion
1222
+ //#region extensions/msteams/src/ai-entity.ts
1223
+ /** AI-generated content entity added to every outbound AI message. */
1224
+ const AI_GENERATED_ENTITY = {
1225
+ type: "https://schema.org/Message",
1226
+ "@type": "Message",
1227
+ "@id": "",
1228
+ additionalType: ["AIGeneratedContent"]
1229
+ };
1230
+ //#endregion
1326
1231
  //#region extensions/msteams/src/mentions.ts
1327
1232
  /**
1328
1233
  * Check whether an ID looks like a valid Teams user/bot identifier.
@@ -1376,7 +1281,7 @@ async function withRevokedProxyFallback(params) {
1376
1281
  try {
1377
1282
  return await params.run();
1378
1283
  } catch (err) {
1379
- if (!require_setup_surface.isRevokedProxyError(err)) throw err;
1284
+ if (!require_channel_setup.isRevokedProxyError(err)) throw err;
1380
1285
  params.onRevokedLog?.();
1381
1286
  return await params.onRevoked();
1382
1287
  }
@@ -1384,6 +1289,12 @@ async function withRevokedProxyFallback(params) {
1384
1289
  //#endregion
1385
1290
  //#region extensions/msteams/src/sdk-proactive.ts
1386
1291
  const loadMSTeamsApiModule = (0, openclaw_plugin_sdk_lazy_runtime.createLazyRuntimeModule)(() => import("@microsoft/teams.api"));
1292
+ async function quoteMSTeamsActivity(activity, messageId) {
1293
+ const { MessageActivityInput } = await loadMSTeamsApiModule();
1294
+ if (typeof activity === "string") return new MessageActivityInput(activity).prependQuote(messageId);
1295
+ if (activity.type !== "message") return activity;
1296
+ return MessageActivityInput.from(activity).prependQuote(messageId);
1297
+ }
1387
1298
  function resolveThreadedConversationId(conversationId, threadActivityId) {
1388
1299
  if (!threadActivityId) return conversationId.split(";")[0] ?? conversationId;
1389
1300
  return `${conversationId.split(";")[0] ?? conversationId};messageid=${threadActivityId}`;
@@ -1481,7 +1392,7 @@ function mergeReferenceIntoActivity(activity, ref) {
1481
1392
  async function sendMSTeamsActivityWithReference(app, source, activity, options) {
1482
1393
  const ref = buildSdkConversationReference(source, options);
1483
1394
  const activities = (await getApiClientForReference(app, ref)).conversations.activities(ref.conversation.id);
1484
- const activityWithRef = mergeReferenceIntoActivity(activity, ref);
1395
+ const activityWithRef = mergeReferenceIntoActivity(options?.quoteActivityId ? await quoteMSTeamsActivity(activity, options.quoteActivityId) : activity, ref);
1485
1396
  const isTargeted = activityWithRef.recipient?.isTargeted === true;
1486
1397
  if (isTargeted && ref.conversation.conversationType === "personal") throw new Error("Targeted messages are not supported in 1:1 (personal) chats.");
1487
1398
  const activityId = typeof activityWithRef.id === "string" ? activityWithRef.id : void 0;
@@ -1507,15 +1418,6 @@ async function deleteMSTeamsActivityWithReference(app, source, activityId, optio
1507
1418
  return (await getApiClientForReference(app, ref)).conversations.activities(ref.conversation.id).delete(activityId);
1508
1419
  }
1509
1420
  //#endregion
1510
- //#region extensions/msteams/src/ai-entity.ts
1511
- /** AI-generated content entity added to every outbound AI message. */
1512
- const AI_GENERATED_ENTITY = {
1513
- type: "https://schema.org/Message",
1514
- "@type": "Message",
1515
- "@id": "",
1516
- additionalType: ["AIGeneratedContent"]
1517
- };
1518
- //#endregion
1519
1421
  //#region extensions/msteams/src/messenger.ts
1520
1422
  /**
1521
1423
  * MSTeams-specific media size limit (100MB).
@@ -1591,12 +1493,9 @@ function resolveRetryOptions(retry) {
1591
1493
  };
1592
1494
  }
1593
1495
  function computeRetryDelayMs(attempt, classification, opts) {
1594
- if (classification.retryAfterMs != null) return clampMs(classification.retryAfterMs, opts.maxDelayMs);
1496
+ if (classification.kind === "replay-safe" && classification.retryAfterMs != null) return clampMs(classification.retryAfterMs, opts.maxDelayMs);
1595
1497
  return clampMs(opts.baseDelayMs * 2 ** Math.max(0, attempt - 1), opts.maxDelayMs);
1596
1498
  }
1597
- function shouldRetry(classification) {
1598
- return classification.kind === "throttled" || classification.kind === "transient";
1599
- }
1600
1499
  function renderReplyPayloadsToMessages(replies, options) {
1601
1500
  const out = [];
1602
1501
  const chunkLimit = Math.min(options.textChunkLimit, 4e3);
@@ -1720,34 +1619,35 @@ async function sendMSTeamsMessages(params) {
1720
1619
  const retryOptions = resolveRetryOptions(params.retry);
1721
1620
  const sendWithRetry = async (sendOnce, meta) => {
1722
1621
  if (!retryOptions.enabled) return await sendOnce();
1723
- for (const attempt of Array.from({ length: retryOptions.maxAttempts }, (_, index) => index + 1)) try {
1724
- return await sendOnce();
1725
- } catch (err) {
1726
- const classification = require_setup_surface.classifyMSTeamsSendError(err);
1727
- if (!(attempt < retryOptions.maxAttempts && shouldRetry(classification))) throw err;
1728
- const delayMs = computeRetryDelayMs(attempt, classification, retryOptions);
1729
- const nextAttempt = attempt + 1;
1730
- params.onRetry?.({
1731
- messageIndex: meta.messageIndex,
1732
- messageCount: meta.messageCount,
1733
- nextAttempt,
1734
- maxAttempts: retryOptions.maxAttempts,
1735
- delayMs,
1736
- classification
1737
- });
1738
- await (0, openclaw_plugin_sdk_text_utility_runtime.sleep)(delayMs);
1739
- }
1740
- throw new Error("unreachable Teams send retry loop exit");
1622
+ return await (0, openclaw_plugin_sdk_retry_runtime.retryAsync)(sendOnce, {
1623
+ attempts: retryOptions.maxAttempts,
1624
+ minDelayMs: 0,
1625
+ maxDelayMs: retryOptions.maxDelayMs,
1626
+ shouldRetry: (err) => require_channel_setup.classifyMSTeamsSendError(err).kind === "replay-safe",
1627
+ delayMs: ({ attempt, err }) => computeRetryDelayMs(attempt, require_channel_setup.classifyMSTeamsSendError(err), retryOptions),
1628
+ onRetry: ({ attempt, err, delayMs }) => {
1629
+ params.onRetry?.({
1630
+ messageIndex: meta.messageIndex,
1631
+ messageCount: meta.messageCount,
1632
+ nextAttempt: attempt + 1,
1633
+ maxAttempts: retryOptions.maxAttempts,
1634
+ delayMs,
1635
+ classification: require_channel_setup.classifyMSTeamsSendError(err)
1636
+ });
1637
+ },
1638
+ sleep: (delayMs) => (0, openclaw_plugin_sdk_runtime_env.sleepWithAbort)(delayMs)
1639
+ });
1741
1640
  };
1742
1641
  let providerDispatchStarted = false;
1743
1642
  const sendMessageInContext = async (sendFn, message, messageIndex) => {
1643
+ let activity;
1744
1644
  let pendingUploadId;
1745
1645
  let response;
1746
1646
  try {
1747
1647
  response = await sendWithRetry(async () => {
1748
- const activity = await buildActivity(message, params.conversationRef, params.tokenProvider, params.sharePointSiteId, params.mediaMaxBytes, { feedbackLoopEnabled: params.feedbackLoopEnabled });
1749
- pendingUploadId = typeof activity["_pendingUploadId"] === "string" ? activity["_pendingUploadId"] : void 0;
1750
- if (pendingUploadId) delete activity["_pendingUploadId"];
1648
+ activity ??= await buildActivity(message, params.conversationRef, params.tokenProvider, params.sharePointSiteId, params.mediaMaxBytes, { feedbackLoopEnabled: params.feedbackLoopEnabled });
1649
+ pendingUploadId ??= typeof activity["_pendingUploadId"] === "string" ? activity["_pendingUploadId"] : void 0;
1650
+ delete activity["_pendingUploadId"];
1751
1651
  providerDispatchStarted = true;
1752
1652
  return await sendFn(activity);
1753
1653
  }, {
@@ -1846,48 +1746,18 @@ Object.defineProperty(exports, "extractMessageId", {
1846
1746
  return extractMessageId;
1847
1747
  }
1848
1748
  });
1849
- Object.defineProperty(exports, "fetchChannelMessage", {
1850
- enumerable: true,
1851
- get: function() {
1852
- return fetchChannelMessage;
1853
- }
1854
- });
1855
- Object.defineProperty(exports, "fetchChatMessageText", {
1856
- enumerable: true,
1857
- get: function() {
1858
- return fetchChatMessageText;
1859
- }
1860
- });
1861
- Object.defineProperty(exports, "fetchThreadReplies", {
1862
- enumerable: true,
1863
- get: function() {
1864
- return fetchThreadReplies;
1865
- }
1866
- });
1867
1749
  Object.defineProperty(exports, "formatMSTeamsMarkdown", {
1868
1750
  enumerable: true,
1869
1751
  get: function() {
1870
1752
  return formatMSTeamsMarkdown;
1871
1753
  }
1872
1754
  });
1873
- Object.defineProperty(exports, "formatThreadContext", {
1874
- enumerable: true,
1875
- get: function() {
1876
- return formatThreadContext;
1877
- }
1878
- });
1879
1755
  Object.defineProperty(exports, "getDriveItemProperties", {
1880
1756
  enumerable: true,
1881
1757
  get: function() {
1882
1758
  return getDriveItemProperties;
1883
1759
  }
1884
1760
  });
1885
- Object.defineProperty(exports, "getMSTeamsReactionEmoji", {
1886
- enumerable: true,
1887
- get: function() {
1888
- return getMSTeamsReactionEmoji;
1889
- }
1890
- });
1891
1761
  Object.defineProperty(exports, "getPendingUpload", {
1892
1762
  enumerable: true,
1893
1763
  get: function() {
@@ -1942,12 +1812,6 @@ Object.defineProperty(exports, "requiresFileConsent", {
1942
1812
  return requiresFileConsent;
1943
1813
  }
1944
1814
  });
1945
- Object.defineProperty(exports, "resolveMSTeamsReactionEmoji", {
1946
- enumerable: true,
1947
- get: function() {
1948
- return resolveMSTeamsReactionEmoji;
1949
- }
1950
- });
1951
1815
  Object.defineProperty(exports, "sendMSTeamsActivityWithReference", {
1952
1816
  enumerable: true,
1953
1817
  get: function() {
@@ -1972,12 +1836,6 @@ Object.defineProperty(exports, "setPendingUploadActivityIdFs", {
1972
1836
  return setPendingUploadActivityIdFs;
1973
1837
  }
1974
1838
  });
1975
- Object.defineProperty(exports, "stripHtmlFromTeamsMessage", {
1976
- enumerable: true,
1977
- get: function() {
1978
- return stripHtmlFromTeamsMessage;
1979
- }
1980
- });
1981
1839
  Object.defineProperty(exports, "updateMSTeamsActivityWithReference", {
1982
1840
  enumerable: true,
1983
1841
  get: function() {
@@ -1,7 +1,7 @@
1
- const require_resolve_allowlist = require("./resolve-allowlist-C6YcNC9a.cjs");
1
+ const require_resolve_allowlist = require("./resolve-allowlist-CWbvAW4v.cjs");
2
+ let openclaw_plugin_sdk_runtime_env = require("openclaw/plugin-sdk/runtime-env");
2
3
  let openclaw_plugin_sdk_provider_auth = require("openclaw/plugin-sdk/provider-auth");
3
4
  let openclaw_plugin_sdk_provider_auth_runtime = require("openclaw/plugin-sdk/provider-auth-runtime");
4
- let openclaw_plugin_sdk_runtime_env = require("openclaw/plugin-sdk/runtime-env");
5
5
  //#region extensions/msteams/src/oauth.flow.ts
6
6
  function shouldUseManualOAuthFlow(isRemote) {
7
7
  return isRemote || (0, openclaw_plugin_sdk_runtime_env.isWSL2Sync)();
@@ -2,7 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  let openclaw_plugin_sdk_qa_runner_runtime = require("openclaw/plugin-sdk/qa-runner-runtime");
3
3
  //#region extensions/msteams/src/qa/cli.ts
4
4
  const DEFAULT_MSTEAMS_QA_SCENARIOS = ["channel-canary"];
5
- const loadMSTeamsQaAdapterRuntime = (0, openclaw_plugin_sdk_qa_runner_runtime.createLazyCliRuntimeLoader)(() => Promise.resolve().then(() => require("./adapter.runtime-DEYjslFX.cjs")));
5
+ const loadMSTeamsQaAdapterRuntime = (0, openclaw_plugin_sdk_qa_runner_runtime.createLazyCliRuntimeLoader)(() => Promise.resolve().then(() => require("./adapter.runtime-8g-MOPfb.cjs")));
6
6
  async function runQaMSTeams(options) {
7
7
  await (0, openclaw_plugin_sdk_qa_runner_runtime.runLiveTransportQaSuiteCommand)({
8
8
  channelId: "msteams",
@@ -0,0 +1,149 @@
1
+ const require_resolve_allowlist = require("./resolve-allowlist-CWbvAW4v.cjs");
2
+ let openclaw_plugin_sdk_html_entity_runtime = require("openclaw/plugin-sdk/html-entity-runtime");
3
+ //#region extensions/msteams/src/graph-thread.ts
4
+ /**
5
+ * Strip HTML tags from Teams message content, preserving @mention display names.
6
+ * Teams wraps mentions in <at>Name</at> tags.
7
+ */
8
+ function stripHtmlFromTeamsMessage(html) {
9
+ let text = html.replace(/<at[^>]*>(.*?)<\/at>/gi, "@$1");
10
+ text = text.replace(/<[^>]*>/g, " ");
11
+ text = (0, openclaw_plugin_sdk_html_entity_runtime.decodeHtmlEntities)(text).replaceAll("\xA0", " ");
12
+ return text.replace(/\s+/g, " ").trim();
13
+ }
14
+ /**
15
+ * Fetch a single channel message (the parent/root of a thread).
16
+ * Returns undefined on error so callers can degrade gracefully.
17
+ */
18
+ async function fetchChannelMessage(token, groupId, channelId, messageId, deadline) {
19
+ const path = `/teams/${encodeURIComponent(groupId)}/channels/${encodeURIComponent(channelId)}/messages/${encodeURIComponent(messageId)}`;
20
+ try {
21
+ return await require_resolve_allowlist.fetchGraphJson({
22
+ token,
23
+ path,
24
+ ...deadline ? { deadline } : {}
25
+ });
26
+ } catch {
27
+ return;
28
+ }
29
+ }
30
+ /**
31
+ * Fetch a single chat message's full text via Graph and return plain text.
32
+ *
33
+ * Used to recover the complete quoted message for Teams quote replies: the
34
+ * inbound blockquote only carries a Teams-truncated `preview` snippet. The
35
+ * app-only `GET /chats/{chatId}/messages/{messageId}` endpoint IS permitted
36
+ * with the `Chat.Read.All` application permission.
37
+ *
38
+ * Returns undefined on any failure so callers degrade to the truncated preview.
39
+ */
40
+ async function fetchChatMessageText(token, chatId, messageId, deadline) {
41
+ const path = `/chats/${encodeURIComponent(chatId)}/messages/${encodeURIComponent(messageId)}`;
42
+ try {
43
+ const msg = await require_resolve_allowlist.fetchGraphJson({
44
+ token,
45
+ path,
46
+ ...deadline ? { deadline } : {}
47
+ });
48
+ const raw = msg.body?.content ?? "";
49
+ return (msg.body?.contentType === "html" ? stripHtmlFromTeamsMessage(raw) : raw.trim()) || void 0;
50
+ } catch {
51
+ return;
52
+ }
53
+ }
54
+ /**
55
+ * Fetch thread replies for a channel message, ordered chronologically.
56
+ *
57
+ * **Limitation:** The Graph API replies endpoint (`/messages/{id}/replies`) does not
58
+ * support `$orderby`, so results are always returned in ascending (oldest-first) order.
59
+ * Combined with the `$top` cap of 50, this means only the **oldest 50 replies** are
60
+ * returned for long threads — newer replies are silently omitted. There is currently no
61
+ * Graph API workaround for this; pagination via `@odata.nextLink` can retrieve more
62
+ * replies but still in ascending order only.
63
+ */
64
+ async function fetchThreadReplies(token, groupId, channelId, messageId, limit = 50, deadline) {
65
+ return (await require_resolve_allowlist.fetchGraphJson({
66
+ token,
67
+ path: `/teams/${encodeURIComponent(groupId)}/channels/${encodeURIComponent(channelId)}/messages/${encodeURIComponent(messageId)}/replies?$top=${Math.min(Math.max(limit, 1), 50)}`,
68
+ ...deadline ? { deadline } : {}
69
+ })).value ?? [];
70
+ }
71
+ /**
72
+ * Format thread messages into a context string for the agent.
73
+ * Skips the current message (by id) and blank messages.
74
+ */
75
+ function formatThreadContext(messages, currentMessageId) {
76
+ const lines = [];
77
+ for (const msg of messages) {
78
+ if (msg.id && msg.id === currentMessageId) continue;
79
+ const sender = msg.from?.user?.displayName ?? msg.from?.application?.displayName ?? "unknown";
80
+ const contentType = msg.body?.contentType ?? "text";
81
+ const rawContent = msg.body?.content ?? "";
82
+ const content = contentType === "html" ? stripHtmlFromTeamsMessage(rawContent) : rawContent.trim();
83
+ if (!content) continue;
84
+ lines.push(`${sender}: ${content}`);
85
+ }
86
+ return lines.join("\n");
87
+ }
88
+ //#endregion
89
+ //#region extensions/msteams/src/reaction-types.ts
90
+ const TEAMS_REACTION_EMOJI = {
91
+ like: "👍",
92
+ heart: "❤️",
93
+ laugh: "😆",
94
+ surprised: "😮",
95
+ sad: "😢",
96
+ angry: "😡"
97
+ };
98
+ const TEAMS_REACTION_TYPES = Object.keys(TEAMS_REACTION_EMOJI);
99
+ function getMSTeamsReactionEmoji(raw) {
100
+ return TEAMS_REACTION_EMOJI[raw.trim().toLowerCase()];
101
+ }
102
+ function resolveMSTeamsReactionEmoji(raw) {
103
+ const normalized = raw.trim();
104
+ if (!normalized) throw new Error(`Reaction type is required. Common types: ${TEAMS_REACTION_TYPES.join(", ")}`);
105
+ return getMSTeamsReactionEmoji(normalized) ?? normalized;
106
+ }
107
+ //#endregion
108
+ Object.defineProperty(exports, "fetchChannelMessage", {
109
+ enumerable: true,
110
+ get: function() {
111
+ return fetchChannelMessage;
112
+ }
113
+ });
114
+ Object.defineProperty(exports, "fetchChatMessageText", {
115
+ enumerable: true,
116
+ get: function() {
117
+ return fetchChatMessageText;
118
+ }
119
+ });
120
+ Object.defineProperty(exports, "fetchThreadReplies", {
121
+ enumerable: true,
122
+ get: function() {
123
+ return fetchThreadReplies;
124
+ }
125
+ });
126
+ Object.defineProperty(exports, "formatThreadContext", {
127
+ enumerable: true,
128
+ get: function() {
129
+ return formatThreadContext;
130
+ }
131
+ });
132
+ Object.defineProperty(exports, "getMSTeamsReactionEmoji", {
133
+ enumerable: true,
134
+ get: function() {
135
+ return getMSTeamsReactionEmoji;
136
+ }
137
+ });
138
+ Object.defineProperty(exports, "resolveMSTeamsReactionEmoji", {
139
+ enumerable: true,
140
+ get: function() {
141
+ return resolveMSTeamsReactionEmoji;
142
+ }
143
+ });
144
+ Object.defineProperty(exports, "stripHtmlFromTeamsMessage", {
145
+ enumerable: true,
146
+ get: function() {
147
+ return stripHtmlFromTeamsMessage;
148
+ }
149
+ });