@openclaw/msteams 2026.10.1 → 2026.10.5-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. package/dist/.setup/{adapter.runtime-D0HYByze.cjs → adapter.runtime-JoPydWqP.cjs} +1 -1
  2. package/dist/.setup/{approval-handler.runtime-C-RJ3wXc.cjs → approval-handler.runtime-bUN9icMr.cjs} +3 -3
  3. package/dist/.setup/{bot-framework-service-url-BUhTe8F3.cjs → bot-framework-service-url-CPp4d-Q6.cjs} +1 -5
  4. package/dist/.setup/{channel-BFhXodl2.cjs → channel-Cifn9fsv.cjs} +230 -430
  5. package/dist/.setup/{channel.runtime-D9jrw2SN.cjs → channel.runtime-DWRAolil.cjs} +70 -44
  6. package/dist/.setup/{channel.setup-ss0TO-ap.cjs → channel.setup-BjbHugkL.cjs} +5 -7
  7. package/dist/.setup/{config-schema-0KoBzb0t.cjs → config-schema-Dk0mRIam.cjs} +1 -1
  8. package/dist/.setup/{conversation-store-state-f7V8CVNy.cjs → conversation-store-state-DprmOfl7.cjs} +103 -236
  9. package/dist/.setup/{monitor-DfSPCRkk.cjs → monitor-C9x_CJhY.cjs} +173 -322
  10. package/dist/.setup/oauth-CWJ85AMw.cjs +55 -0
  11. package/dist/.setup/{reaction-types-B-GEv57k.cjs → reaction-types-Ig9sQJuR.cjs} +3 -3
  12. package/dist/.setup/{resolve-allowlist-Ct9yxQUw.cjs → resolve-allowlist-DdDBVCzl.cjs} +77 -174
  13. package/dist/.setup/{send-7VV1iCai.cjs → send-rJpcVtRp.cjs} +8 -9
  14. package/dist/.setup/{setup-plugin-api-B0OFG32J.cjs → setup-plugin-api-DfoVOqMJ.cjs} +1 -1
  15. package/dist/.setup/{thread-session-ClI-lSyG.cjs → thread-session-B74FC1Id.cjs} +1 -1
  16. package/dist/.setup/{token-config-DOt3XwVa.cjs → token-config-CqIh8z7Q.cjs} +6 -7
  17. package/dist/api.cjs +2 -2
  18. package/dist/channel-config-api.cjs +1 -1
  19. package/dist/channel-plugin-api.cjs +1 -1
  20. package/dist/directory-contract-api.cjs +2 -2
  21. package/dist/doctor-contract-api.cjs +1 -1
  22. package/dist/qa-runner-api.cjs +9 -10
  23. package/dist/setup-entry.cjs +1 -1
  24. package/dist/setup-plugin-api.cjs +1 -1
  25. package/package.json +4 -4
  26. package/dist/.setup/oauth-CYxMYIOQ.cjs +0 -102
@@ -1,15 +1,15 @@
1
1
  const require_rolldown_runtime = require("./rolldown-runtime-BloeesfJ.cjs");
2
2
  const require_runtime = require("./runtime-gZTAuFux.cjs");
3
3
  require("../runtime-api.cjs");
4
- const require_resolve_allowlist = require("./resolve-allowlist-Ct9yxQUw.cjs");
5
- const require_bot_framework_service_url = require("./bot-framework-service-url-BUhTe8F3.cjs");
6
- const require_token_config = require("./token-config-DOt3XwVa.cjs");
7
- const require_channel = require("./channel-BFhXodl2.cjs");
8
- const require_thread_session = require("./thread-session-ClI-lSyG.cjs");
9
- const require_channel_setup = require("./channel.setup-ss0TO-ap.cjs");
4
+ const require_resolve_allowlist = require("./resolve-allowlist-DdDBVCzl.cjs");
5
+ const require_bot_framework_service_url = require("./bot-framework-service-url-CPp4d-Q6.cjs");
6
+ const require_token_config = require("./token-config-CqIh8z7Q.cjs");
7
+ const require_channel = require("./channel-Cifn9fsv.cjs");
8
+ const require_thread_session = require("./thread-session-B74FC1Id.cjs");
9
+ const require_channel_setup = require("./channel.setup-BjbHugkL.cjs");
10
10
  const require_approval_card = require("./approval-card-DWPDItvq.cjs");
11
- const require_conversation_store_state = require("./conversation-store-state-f7V8CVNy.cjs");
12
- const require_reaction_types = require("./reaction-types-B-GEv57k.cjs");
11
+ const require_conversation_store_state = require("./conversation-store-state-DprmOfl7.cjs");
12
+ const require_reaction_types = require("./reaction-types-Ig9sQJuR.cjs");
13
13
  let openclaw_plugin_sdk_channel_outbound = require("openclaw/plugin-sdk/channel-outbound");
14
14
  let openclaw_plugin_sdk_string_coerce_runtime = require("openclaw/plugin-sdk/string-coerce-runtime");
15
15
  let openclaw_plugin_sdk_allow_from = require("openclaw/plugin-sdk/allow-from");
@@ -17,6 +17,7 @@ let openclaw_plugin_sdk_provider_http = require("openclaw/plugin-sdk/provider-ht
17
17
  let openclaw_plugin_sdk_account_id = require("openclaw/plugin-sdk/account-id");
18
18
  let openclaw_plugin_sdk_media_runtime = require("openclaw/plugin-sdk/media-runtime");
19
19
  let openclaw_plugin_sdk_ssrf_runtime = require("openclaw/plugin-sdk/ssrf-runtime");
20
+ let node_dns_promises = require("node:dns/promises");
20
21
  let openclaw_plugin_sdk_ssrf_policy = require("openclaw/plugin-sdk/ssrf-policy");
21
22
  let openclaw_plugin_sdk_number_runtime = require("openclaw/plugin-sdk/number-runtime");
22
23
  let openclaw_plugin_sdk_text_utility_runtime = require("openclaw/plugin-sdk/text-utility-runtime");
@@ -50,13 +51,6 @@ const MAX_LEARNING_ENTRIES = 1e4;
50
51
  function learningStoreKey(storePath, sessionKey) {
51
52
  return node_crypto.default.createHash("sha256").update(`${storePath}\0${sessionKey}`, "utf8").digest("hex");
52
53
  }
53
- function appendFeedbackLearning(current, prepared) {
54
- return {
55
- sessionKey: prepared.sessionKey,
56
- learnings: [...current?.learnings ?? [], prepared.learning].slice(-10),
57
- updatedAt: prepared.updatedAt
58
- };
59
- }
60
54
  async function storeSessionLearning(params) {
61
55
  const store = require_runtime.getMSTeamsRuntime().state.openKeyedStore({
62
56
  namespace: LEARNINGS_NAMESPACE,
@@ -74,7 +68,11 @@ async function storeSessionLearning(params) {
74
68
  const result = await store.compareAndApply(key, observed.comparison, {
75
69
  operation: "update",
76
70
  action: "set",
77
- value: appendFeedbackLearning(observed.value, prepared)
71
+ value: {
72
+ sessionKey: prepared.sessionKey,
73
+ learnings: [...observed.value?.learnings ?? [], prepared.learning].slice(-10),
74
+ updatedAt: prepared.updatedAt
75
+ }
78
76
  });
79
77
  if (result.status !== "conflict") return;
80
78
  observed = result.current;
@@ -99,7 +97,6 @@ async function runFeedbackReflection(params) {
99
97
  sessionKey,
100
98
  conversationId: params.conversationId,
101
99
  conversationKind: params.conversationKind,
102
- thumbedDownResponse: params.thumbedDownResponse,
103
100
  userComment: params.userComment,
104
101
  cooldownMs,
105
102
  onRecordError: (err) => log.debug?.("reflection session record failed", { error: require_channel_setup.formatUnknownError(err) }),
@@ -427,6 +424,14 @@ async function admitMSTeamsMessage(params) {
427
424
  const { dmPolicy, senderId, senderName, pairing, isDirectMessage, hasConflictingConversationScope, channelGate, senderAccess, commandAccess, allowNameMatching, groupPolicy, msteamsCfg } = access;
428
425
  const effectiveDmAllowFrom = senderAccess.effectiveAllowFrom;
429
426
  const effectiveGroupAllowFrom = senderAccess.effectiveGroupAllowFrom;
427
+ const saveConversationReference = () => params.conversationStore.upsert(params.conversationId, params.conversationRef).catch((err) => {
428
+ params.log.debug?.("failed to save conversation reference", { error: require_channel_setup.formatUnknownError(err) });
429
+ });
430
+ const dropGroupMessage = (reason, details) => {
431
+ params.log.info(reason, details);
432
+ params.log.debug?.(reason, details);
433
+ return null;
434
+ };
430
435
  if (hasConflictingConversationScope) {
431
436
  params.log.info("dropping message (conflicting conversation scope)", { conversationId: params.conversationId });
432
437
  params.log.debug?.("dropping message (conflicting conversation scope)");
@@ -448,9 +453,7 @@ async function admitMSTeamsMessage(params) {
448
453
  allowNameMatching
449
454
  });
450
455
  if (senderAccess.decision === "pairing") {
451
- params.conversationStore.upsert(params.conversationId, params.conversationRef).catch((err) => {
452
- params.log.debug?.("failed to save conversation reference", { error: require_channel_setup.formatUnknownError(err) });
453
- });
456
+ saveConversationReference();
454
457
  if (await pairing.upsertPairingRequest({
455
458
  id: senderId,
456
459
  meta: { name: senderName }
@@ -478,33 +481,15 @@ async function admitMSTeamsMessage(params) {
478
481
  return null;
479
482
  }
480
483
  if (!isDirectMessage && msteamsCfg) {
481
- if (channelGate.allowlistConfigured && !channelGate.allowed) {
482
- params.log.info("dropping group message (not in team/channel allowlist)", {
483
- conversationId: params.conversationId,
484
- teamKey: channelGate.teamKey ?? "none",
485
- channelKey: channelGate.channelKey ?? "none",
486
- channelMatchKey: channelGate.channelMatchKey ?? "none",
487
- channelMatchSource: channelGate.channelMatchSource ?? "none"
488
- });
489
- params.log.debug?.("dropping group message (not in team/channel allowlist)", {
490
- conversationId: params.conversationId,
491
- teamKey: channelGate.teamKey ?? "none",
492
- channelKey: channelGate.channelKey ?? "none",
493
- channelMatchKey: channelGate.channelMatchKey ?? "none",
494
- channelMatchSource: channelGate.channelMatchSource ?? "none"
495
- });
496
- return null;
497
- }
498
- if (!senderAccess.allowed && senderAccess.reasonCode === "group_policy_disabled") {
499
- params.log.info("dropping group message (groupPolicy: disabled)", { conversationId: params.conversationId });
500
- params.log.debug?.("dropping group message (groupPolicy: disabled)", { conversationId: params.conversationId });
501
- return null;
502
- }
503
- if (!senderAccess.allowed && (senderAccess.reasonCode === "group_policy_empty_allowlist" || senderAccess.reasonCode === "route_sender_empty")) {
504
- params.log.info("dropping group message (groupPolicy: allowlist, no allowlist)", { conversationId: params.conversationId });
505
- params.log.debug?.("dropping group message (groupPolicy: allowlist, no allowlist)", { conversationId: params.conversationId });
506
- return null;
507
- }
484
+ if (channelGate.allowlistConfigured && !channelGate.allowed) return dropGroupMessage("dropping group message (not in team/channel allowlist)", {
485
+ conversationId: params.conversationId,
486
+ teamKey: channelGate.teamKey ?? "none",
487
+ channelKey: channelGate.channelKey ?? "none",
488
+ channelMatchKey: channelGate.channelMatchKey ?? "none",
489
+ channelMatchSource: channelGate.channelMatchSource ?? "none"
490
+ });
491
+ if (!senderAccess.allowed && senderAccess.reasonCode === "group_policy_disabled") return dropGroupMessage("dropping group message (groupPolicy: disabled)", { conversationId: params.conversationId });
492
+ if (!senderAccess.allowed && (senderAccess.reasonCode === "group_policy_empty_allowlist" || senderAccess.reasonCode === "route_sender_empty")) return dropGroupMessage("dropping group message (groupPolicy: allowlist, no allowlist)", { conversationId: params.conversationId });
508
493
  if (!senderAccess.allowed) {
509
494
  const allowMatch = (0, openclaw_plugin_sdk_allow_from.resolveAllowlistMatchSimple)({
510
495
  allowFrom: effectiveGroupAllowFrom,
@@ -534,9 +519,7 @@ async function admitMSTeamsMessage(params) {
534
519
  });
535
520
  return null;
536
521
  }
537
- params.conversationStore.upsert(params.conversationId, params.conversationRef).catch((err) => {
538
- params.log.debug?.("failed to save conversation reference", { error: require_channel_setup.formatUnknownError(err) });
539
- });
522
+ saveConversationReference();
540
523
  return {
541
524
  ...access,
542
525
  allowTextCommands,
@@ -587,9 +570,7 @@ async function fetchBotFrameworkAttachment(params, kind) {
587
570
  response = await require_resolve_allowlist.safeFetchWithPolicy({
588
571
  url: params.url,
589
572
  policy: params.policy,
590
- fetchFn: params.fetchFn,
591
- fetchFnSupportsDispatcher: params.fetchFnSupportsDispatcher,
592
- resolveFn: params.resolveFn,
573
+ resolveFn: node_dns_promises.lookup,
593
574
  requestInit: { headers },
594
575
  timeoutMs: require_resolve_allowlist.resolveMSTeamsRequestTimeoutMs(params.deadline)
595
576
  });
@@ -635,8 +616,7 @@ async function saveBotFrameworkAttachmentView(params) {
635
616
  filePathHint: params.fileNameHint,
636
617
  maxBytes: params.maxBytes,
637
618
  fallbackContentType: params.contentTypeHint,
638
- subdir: "inbound",
639
- originalFilename: params.preserveFilenames ? params.fileNameHint : void 0
619
+ subdir: "inbound"
640
620
  });
641
621
  } catch (err) {
642
622
  params.logger?.warn?.("msteams botFramework attachmentView save failed", { error: (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err) });
@@ -670,9 +650,6 @@ async function downloadMSTeamsBotFrameworkAttachment(params) {
670
650
  url: baseUrl,
671
651
  accessToken,
672
652
  policy,
673
- fetchFn: params.fetchFn,
674
- fetchFnSupportsDispatcher: params.fetchFnSupportsDispatcher,
675
- resolveFn: params.resolveFn,
676
653
  logger: params.logger,
677
654
  deadline: params.deadline
678
655
  };
@@ -683,15 +660,14 @@ async function downloadMSTeamsBotFrameworkAttachment(params) {
683
660
  const viewId = typeof candidateView?.viewId === "string" && candidateView.viewId ? candidateView.viewId : void 0;
684
661
  if (!viewId) return;
685
662
  if (typeof candidateView?.size === "number" && candidateView.size > 0 && candidateView.size > params.maxBytes) return;
686
- const fileNameHint = typeof params.fileNameHint === "string" && params.fileNameHint || typeof info.name === "string" && info.name || void 0;
687
- const contentTypeHint = typeof params.contentTypeHint === "string" && params.contentTypeHint || typeof info.type === "string" && info.type || void 0;
663
+ const fileNameHint = typeof info.name === "string" && info.name || void 0;
664
+ const contentTypeHint = typeof info.type === "string" && info.type || void 0;
688
665
  const saved = await saveBotFrameworkAttachmentView({
689
666
  ...request,
690
667
  url: `${baseUrl}/views/${encodeURIComponent(viewId)}`,
691
668
  maxBytes: params.maxBytes,
692
669
  fileNameHint,
693
- contentTypeHint,
694
- preserveFilenames: params.preserveFilenames
670
+ contentTypeHint
695
671
  });
696
672
  if (!saved) return;
697
673
  return {
@@ -869,12 +845,6 @@ async function downloadAndStoreMSTeamsRemoteMedia(params) {
869
845
  }
870
846
  //#endregion
871
847
  //#region extensions/msteams/src/attachments/download.ts
872
- function withSourceId(media, sourceId) {
873
- return sourceId ? {
874
- ...media,
875
- sourceId
876
- } : media;
877
- }
878
848
  function resolveDownloadCandidate(att) {
879
849
  const contentType = require_resolve_allowlist.normalizeContentType(att.contentType);
880
850
  const name = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeOptionalString)(att.name) ?? "";
@@ -917,12 +887,8 @@ function resolveDownloadCandidate(att) {
917
887
  };
918
888
  }
919
889
  function scopeCandidatesForUrl(url) {
920
- try {
921
- const host = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeLowercaseStringOrEmpty)(new URL(url).hostname);
922
- return host.endsWith("graph.microsoft.com") || host.endsWith("sharepoint.com") || host.endsWith("1drv.ms") || host.includes("sharepoint") ? ["https://graph.microsoft.com", "https://api.botframework.com"] : ["https://api.botframework.com", "https://graph.microsoft.com"];
923
- } catch {
924
- return ["https://api.botframework.com", "https://graph.microsoft.com"];
925
- }
890
+ const host = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeLowercaseStringOrEmpty)(URL.parse(url)?.hostname);
891
+ return host.endsWith("graph.microsoft.com") || host.endsWith("sharepoint.com") || host.endsWith("1drv.ms") || host.includes("sharepoint") ? ["https://graph.microsoft.com", "https://api.botframework.com"] : ["https://api.botframework.com", "https://graph.microsoft.com"];
926
892
  }
927
893
  function canonicalizeInlineBase64Payload(value) {
928
894
  let cleaned = "";
@@ -957,15 +923,15 @@ async function resolveInlineDataImageMime(inline) {
957
923
  return mime?.startsWith("image/") ? mime : void 0;
958
924
  }
959
925
  async function fetchWithAuthFallback(params) {
960
- const firstAttempt = await require_resolve_allowlist.safeFetchWithPolicy({
926
+ const fetchAttempt = (fetchFn, requestInit) => require_resolve_allowlist.safeFetchWithPolicy({
961
927
  url: params.url,
962
928
  policy: params.policy,
963
- fetchFn: params.fetchFn,
964
- fetchFnSupportsDispatcher: params.fetchFnSupportsDispatcher,
965
- requestInit: params.requestInit,
929
+ fetchFn,
930
+ requestInit,
966
931
  resolveFn: params.resolveFn,
967
932
  timeoutMs: require_resolve_allowlist.resolveMSTeamsRequestTimeoutMs(params.deadline)
968
933
  });
934
+ const firstAttempt = await fetchAttempt(params.fetchFn, params.requestInit);
969
935
  if (firstAttempt.ok) return firstAttempt;
970
936
  if (!params.tokenProvider) return firstAttempt;
971
937
  const tokenProvider = params.tokenProvider;
@@ -982,17 +948,9 @@ async function fetchWithAuthFallback(params) {
982
948
  });
983
949
  const authHeaders = new Headers(params.requestInit?.headers);
984
950
  authHeaders.set("Authorization", `Bearer ${token}`);
985
- const authAttempt = await require_resolve_allowlist.safeFetchWithPolicy({
986
- url: params.url,
987
- policy: params.policy,
988
- fetchFn,
989
- fetchFnSupportsDispatcher: params.fetchFnSupportsDispatcher,
990
- requestInit: {
991
- ...params.requestInit,
992
- headers: authHeaders
993
- },
994
- resolveFn: params.resolveFn,
995
- timeoutMs: require_resolve_allowlist.resolveMSTeamsRequestTimeoutMs(params.deadline)
951
+ const authAttempt = await fetchAttempt(fetchFn, {
952
+ ...params.requestInit,
953
+ headers: authHeaders
996
954
  });
997
955
  await fallbackAttempt.body?.cancel().catch(() => void 0);
998
956
  if (authAttempt.ok || require_resolve_allowlist.isRedirectStatus(authAttempt.status)) return authAttempt;
@@ -1020,12 +978,6 @@ async function downloadMSTeamsAttachments(params) {
1020
978
  });
1021
979
  const maxInlineBytes = params.maxBytes;
1022
980
  candidates.push(...require_resolve_allowlist.extractInlineImageReferences(list).map((candidate) => {
1023
- if (candidate.kind === "data") return {
1024
- kind: "data",
1025
- mediaKind: "image",
1026
- src: candidate.src,
1027
- sourceId: candidate.sourceId
1028
- };
1029
981
  if (candidate.kind === "url") return {
1030
982
  kind: "remote",
1031
983
  mediaKind: "image",
@@ -1034,11 +986,7 @@ async function downloadMSTeamsAttachments(params) {
1034
986
  contentTypeHint: candidate.contentType,
1035
987
  sourceId: candidate.sourceId
1036
988
  };
1037
- return {
1038
- kind: "unavailable",
1039
- mediaKind: "image",
1040
- sourceId: candidate.sourceId
1041
- };
989
+ return Object.assign(candidate, { mediaKind: "image" });
1042
990
  }));
1043
991
  for (const sourceId of resolveUnrepresentedHtmlAttachmentIds(list)) candidates.push({
1044
992
  kind: "unavailable",
@@ -1046,44 +994,30 @@ async function downloadMSTeamsAttachments(params) {
1046
994
  sourceId
1047
995
  });
1048
996
  if (candidates.length === 0) return [];
1049
- const out = [];
1050
997
  let totalInlineBytes = 0;
1051
- for (const candidate of candidates) {
1052
- if (candidate.kind === "unavailable") {
1053
- out.push(withSourceId({ kind: candidate.mediaKind }, candidate.sourceId));
1054
- continue;
1055
- }
998
+ const downloadCandidate = async (candidate) => {
999
+ if (candidate.kind === "unavailable") return;
1056
1000
  if (candidate.kind === "data") {
1057
1001
  const decoded = decodeInlineDataImage(candidate.src, maxInlineBytes, totalInlineBytes);
1058
- if (!decoded) {
1059
- out.push(withSourceId({ kind: candidate.mediaKind }, candidate.sourceId));
1060
- continue;
1061
- }
1002
+ if (!decoded) return;
1062
1003
  totalInlineBytes += decoded.estimatedBytes;
1063
1004
  try {
1064
1005
  const contentType = await resolveInlineDataImageMime(decoded);
1065
- if (!contentType) {
1066
- out.push(withSourceId({ kind: candidate.mediaKind }, candidate.sourceId));
1067
- continue;
1068
- }
1006
+ if (!contentType) return;
1069
1007
  const saved = await require_runtime.getMSTeamsRuntime().channel.media.saveMediaBuffer(decoded.data, contentType, "inbound", params.maxBytes);
1070
- out.push(withSourceId({
1008
+ return {
1071
1009
  path: saved.path,
1072
1010
  contentType: saved.contentType,
1073
1011
  kind: "image"
1074
- }, candidate.sourceId));
1012
+ };
1075
1013
  } catch (err) {
1076
- out.push(withSourceId({ kind: candidate.mediaKind }, candidate.sourceId));
1077
1014
  params.logger?.warn?.("msteams inline attachment decode failed", { error: (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err) });
1078
1015
  }
1079
- continue;
1080
- }
1081
- if (!(0, openclaw_plugin_sdk_ssrf_policy.isHttpsUrlAllowedByHostnameSuffixAllowlist)(candidate.url, allowHosts)) {
1082
- out.push(withSourceId({ kind: candidate.mediaKind }, candidate.sourceId));
1083
- continue;
1016
+ return;
1084
1017
  }
1018
+ if (!(0, openclaw_plugin_sdk_ssrf_policy.isHttpsUrlAllowedByHostnameSuffixAllowlist)(candidate.url, allowHosts)) return;
1085
1019
  try {
1086
- const media = await downloadAndStoreMSTeamsRemoteMedia({
1020
+ return await downloadAndStoreMSTeamsRemoteMedia({
1087
1021
  url: candidate.url,
1088
1022
  filePathHint: candidate.fileHint ?? candidate.url,
1089
1023
  maxBytes: params.maxBytes,
@@ -1094,28 +1028,29 @@ async function downloadMSTeamsAttachments(params) {
1094
1028
  url: (0, openclaw_plugin_sdk_request_url.resolveRequestUrl)(input),
1095
1029
  tokenProvider: params.tokenProvider,
1096
1030
  fetchFn: params.fetchFn,
1097
- fetchFnSupportsDispatcher: params.fetchFnSupportsDispatcher,
1098
1031
  requestInit: init,
1099
1032
  resolveFn: params.resolveFn,
1100
1033
  policy,
1101
1034
  deadline: params.deadline
1102
1035
  })
1103
1036
  });
1104
- out.push(withSourceId(media, candidate.sourceId));
1105
1037
  } catch (err) {
1106
- out.push(withSourceId({ kind: candidate.mediaKind }, candidate.sourceId));
1107
1038
  const msg = (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err);
1108
1039
  params.logger?.warn?.(`msteams attachment download failed host=${safeHostForLog(candidate.url)} error=${msg}`);
1109
1040
  }
1041
+ };
1042
+ const out = [];
1043
+ for (const candidate of candidates) {
1044
+ const media = await downloadCandidate(candidate) ?? { kind: candidate.mediaKind };
1045
+ out.push(candidate.sourceId ? {
1046
+ ...media,
1047
+ sourceId: candidate.sourceId
1048
+ } : media);
1110
1049
  }
1111
1050
  return out;
1112
1051
  }
1113
1052
  function safeHostForLog(url) {
1114
- try {
1115
- return new URL(url).host;
1116
- } catch {
1117
- return "invalid-url";
1118
- }
1053
+ return URL.parse(url)?.host ?? "invalid-url";
1119
1054
  }
1120
1055
  //#endregion
1121
1056
  //#region extensions/msteams/src/attachments/graph.ts
@@ -1143,21 +1078,24 @@ function buildMSTeamsGraphMessageUrl(params) {
1143
1078
  if (!chatId) return;
1144
1079
  return `${require_resolve_allowlist.GRAPH_ROOT}/chats/${encodeURIComponent(chatId)}/messages/${encodeURIComponent(messageId)}`;
1145
1080
  }
1146
- async function releaseGraphResponse(response, release) {
1147
- if (!response.bodyUsed) response.body?.cancel().catch(() => void 0);
1148
- await release();
1149
- }
1150
- async function fetchGraphCollection(params) {
1151
- const fetchFn = params.fetchFn ?? fetch;
1081
+ async function withGraphMediaResponse(params, url, kind, read) {
1152
1082
  const { response, release } = await (0, openclaw_plugin_sdk_ssrf_runtime.fetchWithSsrFGuard)({
1153
- url: params.url,
1154
- fetchImpl: fetchFn,
1083
+ url,
1084
+ fetchImpl: params.fetchFn ?? fetch,
1155
1085
  init: { headers: require_resolve_allowlist.ensureUserAgentHeader({ Authorization: `Bearer ${params.accessToken}` }) },
1156
1086
  policy: params.ssrfPolicy,
1157
- auditContext: "msteams.graph.collection",
1087
+ auditContext: `msteams.graph.${kind}`,
1158
1088
  timeoutMs: require_resolve_allowlist.resolveMSTeamsRequestTimeoutMs(params.deadline)
1159
1089
  });
1160
1090
  try {
1091
+ return await read(response);
1092
+ } finally {
1093
+ if (!response.bodyUsed) response.body?.cancel().catch(() => void 0);
1094
+ await release();
1095
+ }
1096
+ }
1097
+ async function fetchGraphCollection(params) {
1098
+ return withGraphMediaResponse(params, params.url, "collection", async (response) => {
1161
1099
  const status = response.status;
1162
1100
  if (!response.ok) return {
1163
1101
  status,
@@ -1174,9 +1112,7 @@ async function fetchGraphCollection(params) {
1174
1112
  items: []
1175
1113
  };
1176
1114
  }
1177
- } finally {
1178
- await releaseGraphResponse(response, release);
1179
- }
1115
+ });
1180
1116
  }
1181
1117
  function normalizeGraphAttachment(att) {
1182
1118
  let content = att.content;
@@ -1196,11 +1132,8 @@ async function downloadGraphHostedContent(params) {
1196
1132
  let hosted;
1197
1133
  try {
1198
1134
  hosted = await fetchGraphCollection({
1199
- url: `${params.messageUrl}/hostedContents`,
1200
- accessToken: params.accessToken,
1201
- fetchFn: params.fetchFn,
1202
- ssrfPolicy: params.ssrfPolicy,
1203
- deadline: params.deadline
1135
+ ...params,
1136
+ url: `${params.messageUrl}/hostedContents`
1204
1137
  });
1205
1138
  } catch (err) {
1206
1139
  params.logger?.warn?.("msteams graph hostedContents fetch failed", { error: (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err) });
@@ -1221,19 +1154,12 @@ async function downloadGraphHostedContent(params) {
1221
1154
  continue;
1222
1155
  }
1223
1156
  try {
1224
- const valueUrl = `${params.messageUrl}/hostedContents/${encodeURIComponent(item.id)}/$value`;
1225
- const { response: valRes, release } = await (0, openclaw_plugin_sdk_ssrf_runtime.fetchWithSsrFGuard)({
1226
- url: valueUrl,
1227
- fetchImpl: params.fetchFn ?? fetch,
1228
- init: { headers: require_resolve_allowlist.ensureUserAgentHeader({ Authorization: `Bearer ${params.accessToken}` }) },
1229
- policy: params.ssrfPolicy,
1230
- auditContext: "msteams.graph.hostedContent.value",
1231
- timeoutMs: require_resolve_allowlist.resolveMSTeamsRequestTimeoutMs(params.deadline)
1232
- });
1233
- try {
1157
+ const sourceId = item.id;
1158
+ const valueUrl = `${params.messageUrl}/hostedContents/${encodeURIComponent(sourceId)}/$value`;
1159
+ await withGraphMediaResponse(params, valueUrl, "hostedContent.value", async (valRes) => {
1234
1160
  if (!valRes.ok) {
1235
1161
  out.push(createGraphHostedContentFact(item));
1236
- continue;
1162
+ return;
1237
1163
  }
1238
1164
  const saved = await require_runtime.getMSTeamsRuntime().channel.media.saveResponseMedia(valRes, {
1239
1165
  sourceUrl: valueUrl,
@@ -1245,11 +1171,9 @@ async function downloadGraphHostedContent(params) {
1245
1171
  path: saved.path,
1246
1172
  contentType: saved.contentType,
1247
1173
  kind: require_resolve_allowlist.resolveMSTeamsMediaKind({ contentType: saved.contentType }),
1248
- sourceId: item.id
1174
+ sourceId
1249
1175
  });
1250
- } finally {
1251
- await releaseGraphResponse(valRes, release);
1252
- }
1176
+ });
1253
1177
  } catch (err) {
1254
1178
  out.push(createGraphHostedContentFact(item));
1255
1179
  params.logger?.warn?.("msteams graph hostedContent value fetch failed", { error: (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err) });
@@ -1271,6 +1195,16 @@ async function downloadMSTeamsGraphMedia(params) {
1271
1195
  });
1272
1196
  const ssrfPolicy = (0, openclaw_plugin_sdk_ssrf_policy.buildHostnameAllowlistPolicyFromSuffixAllowlist)(policy.allowHosts);
1273
1197
  const messageUrl = params.messageUrl;
1198
+ const logGraphFailure = (phase, err) => {
1199
+ params.logger?.debug?.(`graph media ${phase} failed`, {
1200
+ messageUrl,
1201
+ error: (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err)
1202
+ });
1203
+ params.logger?.warn?.(`msteams graph ${phase} failed`, {
1204
+ error: (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err),
1205
+ ...phase === "message parse" ? { messageUrl } : {}
1206
+ });
1207
+ };
1274
1208
  let accessToken;
1275
1209
  try {
1276
1210
  accessToken = await require_resolve_allowlist.withMSTeamsRequestDeadline({
@@ -1279,11 +1213,7 @@ async function downloadMSTeamsGraphMedia(params) {
1279
1213
  work: () => tokenProvider.getAccessToken("https://graph.microsoft.com")
1280
1214
  });
1281
1215
  } catch (err) {
1282
- params.logger?.debug?.("graph media token acquisition failed", {
1283
- messageUrl,
1284
- error: (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err)
1285
- });
1286
- params.logger?.warn?.("msteams graph token acquisition failed", { error: (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err) });
1216
+ logGraphFailure("token acquisition", err);
1287
1217
  return {
1288
1218
  media: [],
1289
1219
  messageUrl,
@@ -1297,29 +1227,18 @@ async function downloadMSTeamsGraphMedia(params) {
1297
1227
  let referenceAttachments = [];
1298
1228
  let messageStatus;
1299
1229
  try {
1300
- const { response: msgRes, release } = await (0, openclaw_plugin_sdk_ssrf_runtime.fetchWithSsrFGuard)({
1301
- url: messageUrl,
1302
- fetchImpl: fetchFn,
1303
- init: { headers: require_resolve_allowlist.ensureUserAgentHeader({ Authorization: `Bearer ${accessToken}` }) },
1304
- policy: ssrfPolicy,
1305
- auditContext: "msteams.graph.message",
1306
- timeoutMs: require_resolve_allowlist.resolveMSTeamsRequestTimeoutMs(params.deadline)
1307
- });
1308
- try {
1230
+ await withGraphMediaResponse({
1231
+ ...params,
1232
+ accessToken,
1233
+ ssrfPolicy
1234
+ }, messageUrl, "message", async (msgRes) => {
1309
1235
  messageStatus = msgRes.status;
1310
1236
  if (msgRes.ok) {
1311
1237
  let msgData;
1312
1238
  try {
1313
1239
  msgData = await (0, openclaw_plugin_sdk_provider_http.readProviderJsonResponse)(msgRes, "MS Teams Graph message");
1314
1240
  } catch (err) {
1315
- params.logger?.debug?.("graph media message parse failed", {
1316
- messageUrl,
1317
- error: (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err)
1318
- });
1319
- params.logger?.warn?.("msteams graph message parse failed", {
1320
- error: (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err),
1321
- messageUrl
1322
- });
1241
+ logGraphFailure("message parse", err);
1323
1242
  msgData = {};
1324
1243
  }
1325
1244
  messageAttachments = Array.isArray(msgData.attachments) ? msgData.attachments : [];
@@ -1328,15 +1247,9 @@ async function downloadMSTeamsGraphMedia(params) {
1328
1247
  messageUrl,
1329
1248
  status: messageStatus
1330
1249
  });
1331
- } finally {
1332
- await releaseGraphResponse(msgRes, release);
1333
- }
1334
- } catch (err) {
1335
- params.logger?.debug?.("graph media message fetch failed", {
1336
- messageUrl,
1337
- error: (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err)
1338
1250
  });
1339
- params.logger?.warn?.("msteams graph message fetch failed", { error: (0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err) });
1251
+ } catch (err) {
1252
+ logGraphFailure("message fetch", err);
1340
1253
  }
1341
1254
  for (const att of referenceAttachments) {
1342
1255
  const name = att.name ?? "file";
@@ -1383,7 +1296,6 @@ async function downloadMSTeamsGraphMedia(params) {
1383
1296
  url: requestUrl,
1384
1297
  policy,
1385
1298
  fetchFn,
1386
- fetchFnSupportsDispatcher: params.fetchFnSupportsDispatcher,
1387
1299
  requestInit: {
1388
1300
  ...init,
1389
1301
  headers
@@ -1415,12 +1327,7 @@ async function downloadMSTeamsGraphMedia(params) {
1415
1327
  deadline: params.deadline
1416
1328
  });
1417
1329
  const normalizedAttachments = messageAttachments.map(normalizeGraphAttachment);
1418
- const filteredAttachments = sharePointMedia.length > 0 ? normalizedAttachments.filter((att) => {
1419
- if ((0, openclaw_plugin_sdk_string_coerce_runtime.normalizeOptionalLowercaseString)(att.contentType) !== "reference") return true;
1420
- const url = typeof att.contentUrl === "string" ? att.contentUrl : "";
1421
- if (!url) return true;
1422
- return !downloadedReferenceUrls.has(url);
1423
- }) : normalizedAttachments;
1330
+ const filteredAttachments = sharePointMedia.length > 0 ? normalizedAttachments.filter((att) => att.contentType !== "reference" || typeof att.contentUrl !== "string" || !att.contentUrl || !downloadedReferenceUrls.has(att.contentUrl)) : normalizedAttachments;
1424
1331
  let attachmentMedia = [];
1425
1332
  try {
1426
1333
  attachmentMedia = await downloadMSTeamsAttachments({
@@ -1430,7 +1337,6 @@ async function downloadMSTeamsGraphMedia(params) {
1430
1337
  allowHosts: policy.allowHosts,
1431
1338
  authAllowHosts: policy.authAllowHosts,
1432
1339
  fetchFn: params.fetchFn,
1433
- fetchFnSupportsDispatcher: params.fetchFnSupportsDispatcher,
1434
1340
  resolveFn: params.resolveFn,
1435
1341
  deadline: params.deadline,
1436
1342
  preserveFilenames: params.preserveFilenames,
@@ -1506,14 +1412,13 @@ function hasMaterializedMedia(media) {
1506
1412
  return media.some((entry) => Boolean(entry.path));
1507
1413
  }
1508
1414
  async function resolveMSTeamsInboundMedia(params) {
1509
- const { attachments, htmlSummary, maxBytes, tokenProvider, allowHosts, conversationType, conversationId, conversationMessageId, teamAadGroupId, serviceUrl, activity, log, preserveFilenames } = params;
1415
+ const { attachments, htmlSummary, maxBytes, tokenProvider, allowHosts, conversationType, conversationId, conversationMessageId, teamAadGroupId, serviceUrl, activity, log } = params;
1510
1416
  let mediaList = await downloadMSTeamsAttachments({
1511
1417
  attachments,
1512
1418
  maxBytes,
1513
1419
  tokenProvider,
1514
1420
  allowHosts,
1515
1421
  authAllowHosts: params.authAllowHosts,
1516
- preserveFilenames,
1517
1422
  deadline: params.deadline,
1518
1423
  logger: log
1519
1424
  });
@@ -1540,7 +1445,6 @@ async function resolveMSTeamsInboundMedia(params) {
1540
1445
  maxBytes,
1541
1446
  allowHosts,
1542
1447
  authAllowHosts: params.authAllowHosts,
1543
- preserveFilenames,
1544
1448
  deadline: params.deadline
1545
1449
  });
1546
1450
  if (bfMedia.media.length > 0) mediaList = mergeMSTeamsMediaFacts(mediaList, bfMedia.media, { positionallyAligned: false });
@@ -1573,7 +1477,6 @@ async function resolveMSTeamsInboundMedia(params) {
1573
1477
  maxBytes,
1574
1478
  allowHosts,
1575
1479
  authAllowHosts: params.authAllowHosts,
1576
- preserveFilenames,
1577
1480
  deadline: params.deadline,
1578
1481
  logger: log
1579
1482
  });
@@ -1638,8 +1541,7 @@ async function prepareMSTeamsInboundContent(params) {
1638
1541
  channelData: activity.channelData
1639
1542
  },
1640
1543
  log: params.log,
1641
- deadline: params.deadline,
1642
- preserveFilenames: false
1544
+ deadline: params.deadline
1643
1545
  })
1644
1546
  });
1645
1547
  } catch (err) {
@@ -1741,26 +1643,19 @@ function createTeamsReplyStreamController(params) {
1741
1643
  const deferredReplacementLogicalContent = () => {
1742
1644
  return deferredReplacementEntries.map((entry) => entry.payload.text).filter((text) => Boolean(text)).join("\n") || void 0;
1743
1645
  };
1744
- const takeDeferredReplacementPayloads = (replacementFallback) => {
1745
- const payloads = deferredReplacementEntries.flatMap((entry) => {
1746
- if (entry.kind === "payload") return [entry.payload];
1747
- const hasMedia = Boolean(entry.payload.mediaUrl || entry.payload.mediaUrls?.length);
1748
- const text = replacementFallback?.text;
1749
- if (!text && !hasMedia) return [];
1750
- return [{
1751
- ...entry.payload,
1752
- text: text || void 0
1753
- }];
1754
- });
1755
- deferredReplacementEntries = [];
1756
- return payloads;
1757
- };
1646
+ const deferredReplacementPayloads = (replacementFallback) => deferredReplacementEntries.flatMap((entry) => {
1647
+ if (entry.kind === "payload") return [entry.payload];
1648
+ const hasMedia = Boolean(entry.payload.mediaUrl || entry.payload.mediaUrls?.length);
1649
+ const text = replacementFallback?.text;
1650
+ if (!text && !hasMedia) return [];
1651
+ return [{
1652
+ ...entry.payload,
1653
+ text: text || void 0
1654
+ }];
1655
+ });
1758
1656
  const finalizeWithoutReceipt = (logicalContent, canceled = false) => {
1759
- const pending = pendingFinalPayload;
1760
- pendingFinalPayload = void 0;
1761
- const fallback = pending && !canceled ? fallbackPayloadAfterAcknowledgedText(pending) : void 0;
1762
- const postNativePayloads = replacementSettlementPending && !canceled ? takeDeferredReplacementPayloads(fallback) : [];
1763
- if (canceled) deferredReplacementEntries = [];
1657
+ const fallback = pendingFinalPayload && !canceled ? fallbackPayloadAfterAcknowledgedText(pendingFinalPayload) : void 0;
1658
+ const postNativePayloads = replacementSettlementPending && !canceled ? deferredReplacementPayloads(fallback) : [];
1764
1659
  return {
1765
1660
  ...acknowledgedNativeDelivery(),
1766
1661
  ...!canceled && logicalContent ? { logicalContent } : {},
@@ -1920,13 +1815,7 @@ function createTeamsReplyStreamController(params) {
1920
1815
  }
1921
1816
  let logicalContent;
1922
1817
  try {
1923
- if (wasCanceled()) {
1924
- pendingFinalPayload = void 0;
1925
- deferredReplacementEntries = [];
1926
- streamFinalizationPending = false;
1927
- return acknowledgedNativeDelivery();
1928
- }
1929
- if (!streamFinalizationPending) return acknowledgedNativeDelivery();
1818
+ if (wasCanceled() || !streamFinalizationPending) return acknowledgedNativeDelivery();
1930
1819
  if (replacementSettlementPending && replacementFinalPending && pendingFinalPayload?.text) {
1931
1820
  replacementFinalPending = false;
1932
1821
  deferredReplacementEntries.push({
@@ -1962,12 +1851,10 @@ function createTeamsReplyStreamController(params) {
1962
1851
  });
1963
1852
  }
1964
1853
  const result = await stream.close();
1965
- streamFinalizationPending = false;
1966
1854
  if (!result) return finalizeWithoutReceipt(logicalContent, wasCanceled());
1967
1855
  const replacementFallback = replacementSettlementPending && replacementEmitFailed && pendingFinalPayload ? fallbackPayloadAfterAcknowledgedText(pendingFinalPayload) : void 0;
1968
- pendingFinalPayload = void 0;
1969
1856
  const messageId = require_conversation_store_state.extractMessageId(result) ?? acknowledgedStreamId;
1970
- const postNativePayloads = replacementSettlementPending ? takeDeferredReplacementPayloads(replacementFallback) : [];
1857
+ const postNativePayloads = replacementSettlementPending ? deferredReplacementPayloads(replacementFallback) : [];
1971
1858
  const nativeContent = replacementEmitFailed ? acknowledgedText || void 0 : content;
1972
1859
  return {
1973
1860
  visibleReplySent: replacementEmitFailed ? Boolean(nativeContent) : true,
@@ -1979,16 +1866,14 @@ function createTeamsReplyStreamController(params) {
1979
1866
  } catch (err) {
1980
1867
  if (isStreamCancelledError(err)) {
1981
1868
  canceledLocally = true;
1982
- pendingFinalPayload = void 0;
1983
- deferredReplacementEntries = [];
1984
- streamFinalizationPending = false;
1985
1869
  return acknowledgedNativeDelivery();
1986
1870
  }
1987
1871
  streamFailed = true;
1988
- streamFinalizationPending = false;
1989
1872
  params.log?.warn?.(`msteams stream finalize failed: ${(0, openclaw_plugin_sdk_error_runtime.coerceErrorMessage)(err)}`);
1990
1873
  return finalizeWithoutReceipt(logicalContent);
1991
1874
  } finally {
1875
+ pendingFinalPayload = void 0;
1876
+ streamFinalizationPending = false;
1992
1877
  failedSegmentFallbackPrepared = true;
1993
1878
  queuedFinalActivity = void 0;
1994
1879
  replacementEmitFailed = false;
@@ -2077,29 +1962,7 @@ function createMSTeamsReplyDispatcher(params) {
2077
1962
  const typingIndicatorEnabled = typeof msteamsCfg?.typingIndicator === "boolean" ? msteamsCfg.typingIndicator : true;
2078
1963
  const pendingDeliveries = [];
2079
1964
  let pendingSettlement;
2080
- const findPendingNativeDelivery = () => pendingDeliveries.find((candidate) => candidate.native && !candidate.nativeSettled);
2081
- const joinAcceptedContents = (contents) => contents.filter((content) => Boolean(content)).join("\n");
2082
- const sendMessages = async (messages) => {
2083
- return require_conversation_store_state.sendMSTeamsMessages({
2084
- replyStyle: params.replyStyle,
2085
- app: params.app,
2086
- conversationRef: params.conversationRef,
2087
- context: params.context,
2088
- messages,
2089
- retry: {},
2090
- onRetry: (event) => {
2091
- params.log.debug?.("retrying send", {
2092
- replyStyle: params.replyStyle,
2093
- ...event
2094
- });
2095
- },
2096
- tokenProvider: params.tokenProvider,
2097
- sharePointSiteId: params.sharePointSiteId,
2098
- mediaMaxBytes,
2099
- feedbackLoopEnabled,
2100
- serviceUrlBoundary: require_resolve_allowlist.resolveMSTeamsSdkCloudOptions(msteamsCfg)
2101
- });
2102
- };
1965
+ const findPendingNativeDelivery = () => pendingDeliveries.find((candidate) => !candidate.nativeSettled);
2103
1966
  const queueDeliveryFailureSystemEvent = (failure) => {
2104
1967
  const classification = require_channel_setup.classifyMSTeamsSendError(failure.error);
2105
1968
  const errorText = require_channel_setup.formatUnknownError(failure.error);
@@ -2120,26 +1983,21 @@ function createMSTeamsReplyDispatcher(params) {
2120
1983
  const renderReplyPayload = (payload) => {
2121
1984
  return require_conversation_store_state.renderReplyPayloadsToMessages([payload], {
2122
1985
  textChunkLimit: params.textLimit,
2123
- chunkText: true,
2124
- mediaMode: "split",
2125
1986
  tableMode,
2126
1987
  chunkMode
2127
1988
  });
2128
1989
  };
2129
- const deliveryOutcome = (delivery) => {
1990
+ const settlePendingDelivery = (delivery) => {
1991
+ if (delivery.settled || !delivery.blockSettled || !delivery.nativeSettled) return;
1992
+ delivery.settled = true;
2130
1993
  const acceptedParts = [...delivery.nativeResult ? [delivery.nativeResult] : [], ...delivery.blockResults];
2131
1994
  const messageIds = acceptedParts.flatMap((part) => part.messageIds);
2132
- const content = delivery.errors.length > 0 ? joinAcceptedContents(acceptedParts.map((part) => part.content)) : delivery.content;
2133
- return {
1995
+ const content = delivery.errors.length > 0 ? acceptedParts.map((part) => part.content).filter(Boolean).join("\n") : delivery.content;
1996
+ const outcome = {
2134
1997
  visibleReplySent: acceptedParts.length > 0,
2135
1998
  ...messageIds.length > 0 ? { messageIds } : {},
2136
1999
  ...acceptedParts.length > 0 && content !== void 0 ? { content } : {}
2137
2000
  };
2138
- };
2139
- const settlePendingDelivery = (delivery) => {
2140
- if (delivery.settled || !delivery.blockSettled || delivery.native && !delivery.nativeSettled) return;
2141
- delivery.settled = true;
2142
- const outcome = deliveryOutcome(delivery);
2143
2001
  if (delivery.errors.length === 0) {
2144
2002
  delivery.finalization.resolve(outcome);
2145
2003
  return;
@@ -2150,21 +2008,6 @@ function createMSTeamsReplyDispatcher(params) {
2150
2008
  visibleReplySent: true
2151
2009
  }) : error);
2152
2010
  };
2153
- const queueReplyPayload = (payload, messages, native) => {
2154
- const delivery = {
2155
- messages,
2156
- finalization: (0, openclaw_plugin_sdk_extension_shared.createDeferred)(),
2157
- content: payload.text,
2158
- blockResults: [],
2159
- native,
2160
- nativeSettled: !native,
2161
- blockSettled: messages.length === 0,
2162
- settled: false,
2163
- errors: []
2164
- };
2165
- pendingDeliveries.push(delivery);
2166
- return delivery;
2167
- };
2168
2011
  const flushPendingMessages = async () => {
2169
2012
  for (const delivery of pendingDeliveries) {
2170
2013
  if (delivery.blockSettled) continue;
@@ -2174,7 +2017,24 @@ function createMSTeamsReplyDispatcher(params) {
2174
2017
  let lastFailedError;
2175
2018
  const sentIds = [];
2176
2019
  for (const msg of toSend) try {
2177
- const msgIds = await sendMessages([msg]);
2020
+ const msgIds = await require_conversation_store_state.sendMSTeamsMessages({
2021
+ replyStyle: params.replyStyle,
2022
+ app: params.app,
2023
+ conversationRef: params.conversationRef,
2024
+ context: params.context,
2025
+ messages: [msg],
2026
+ onRetry: (event) => {
2027
+ params.log.debug?.("retrying send", {
2028
+ replyStyle: params.replyStyle,
2029
+ ...event
2030
+ });
2031
+ },
2032
+ tokenProvider: params.tokenProvider,
2033
+ sharePointSiteId: params.sharePointSiteId,
2034
+ mediaMaxBytes,
2035
+ feedbackLoopEnabled,
2036
+ serviceUrlBoundary: require_resolve_allowlist.resolveMSTeamsSdkCloudOptions(msteamsCfg)
2037
+ });
2178
2038
  const validIds = msgIds.filter((id) => id.trim() && id !== "unknown");
2179
2039
  if (msgIds.length > 0) delivery.blockResults.push({
2180
2040
  messageIds: validIds,
@@ -2227,7 +2087,17 @@ function createMSTeamsReplyDispatcher(params) {
2227
2087
  visibleReplySent: false,
2228
2088
  suppression: { reason: "no_visible_result" }
2229
2089
  };
2230
- const pending = queueReplyPayload(payload, messages, native);
2090
+ const pending = {
2091
+ messages,
2092
+ finalization: (0, openclaw_plugin_sdk_extension_shared.createDeferred)(),
2093
+ content: payload.text,
2094
+ blockResults: [],
2095
+ nativeSettled: !native,
2096
+ blockSettled: messages.length === 0,
2097
+ settled: false,
2098
+ errors: []
2099
+ };
2100
+ pendingDeliveries.push(pending);
2231
2101
  if (blockStreamingEnabled) await flushPendingMessages();
2232
2102
  settlePendingDelivery(pending);
2233
2103
  return {
@@ -2290,8 +2160,7 @@ function createMSTeamsReplyDispatcher(params) {
2290
2160
  const shouldSuppressDefaultToolProgressMessages = streamController.hasStream() && teamsStreamMode === "progress";
2291
2161
  const progressCallbacks = streamController.hasStream() ? {
2292
2162
  onReasoningStream: async (payload) => {
2293
- const text = typeof payload?.text === "string" ? payload.text : void 0;
2294
- await streamController.pushReasoningProgress(text, { snapshot: payload?.isReasoningSnapshot === true });
2163
+ await streamController.pushReasoningProgress(payload.text, { snapshot: payload.isReasoningSnapshot === true });
2295
2164
  return false;
2296
2165
  },
2297
2166
  onReasoningEnd: () => {
@@ -2301,22 +2170,12 @@ function createMSTeamsReplyDispatcher(params) {
2301
2170
  onToolStart: streamController.pushToolEvent,
2302
2171
  onItemEvent: streamController.pushItemEvent,
2303
2172
  onPlanUpdate: async (payload) => {
2304
- if (payload?.phase !== "update") return false;
2305
- await streamController.pushPlanProgress((0, openclaw_plugin_sdk_channel_outbound.normalizeAgentPlanSteps)(payload.steps), {
2306
- explanation: typeof payload.explanation === "string" ? payload.explanation : void 0,
2307
- explanationFormat: payload.explanationFormat === "plain" ? "plain" : void 0
2308
- });
2173
+ if (payload.phase !== "update") return false;
2174
+ await streamController.pushPlanProgress(payload.steps, payload);
2309
2175
  return false;
2310
2176
  },
2311
2177
  onApprovalEvent: async (payload) => {
2312
- await streamController.pushApprovalEvent({
2313
- ...typeof payload?.phase === "string" ? { phase: payload.phase } : {},
2314
- ...typeof payload?.approvalId === "string" ? { approvalId: payload.approvalId } : {},
2315
- ...typeof payload?.title === "string" ? { title: payload.title } : {},
2316
- ...typeof payload?.command === "string" ? { command: payload.command } : {},
2317
- ...typeof payload?.reason === "string" ? { reason: payload.reason } : {},
2318
- ...typeof payload?.message === "string" ? { message: payload.message } : {}
2319
- });
2178
+ await streamController.pushApprovalEvent(payload);
2320
2179
  return false;
2321
2180
  }
2322
2181
  } : {};
@@ -2354,7 +2213,7 @@ async function dispatchMSTeamsInboundTurn(params) {
2354
2213
  const teamsFrom = isDirectMessage ? `msteams:${senderId}` : isChannel ? `msteams:channel:${conversationId}` : `msteams:group:${conversationId}`;
2355
2214
  const teamsTo = isDirectMessage ? `user:${senderId}` : `conversation:${conversationId}`;
2356
2215
  const envelopeFrom = isDirectMessage ? senderName : conversationType;
2357
- const buildEnvelope = (0, openclaw_plugin_sdk_channel_inbound.createChannelInboundEnvelopeBuilder)({
2216
+ const buildEnvelope = await (0, openclaw_plugin_sdk_channel_inbound.createChannelInboundEnvelopeBuilderAsync)({
2358
2217
  cfg,
2359
2218
  route
2360
2219
  });
@@ -2719,7 +2578,7 @@ function resolveParentCacheExpiresAt(nowRaw) {
2719
2578
  const nowMs = (0, openclaw_plugin_sdk_number_runtime.asDateTimestampMs)(nowRaw);
2720
2579
  return nowMs === void 0 ? void 0 : (0, openclaw_plugin_sdk_number_runtime.resolveExpiresAtMsFromDurationMs)(PARENT_CACHE_TTL_MS, { nowMs });
2721
2580
  }
2722
- async function fetchParentMessageCached(token, groupId, channelId, parentId, fetchParent = require_reaction_types.fetchChannelMessage) {
2581
+ async function fetchParentMessageCached(token, groupId, channelId, parentId, deadline) {
2723
2582
  const key = buildParentCacheKey(groupId, channelId, parentId);
2724
2583
  const now = (0, openclaw_plugin_sdk_number_runtime.asDateTimestampMs)(Date.now());
2725
2584
  const cached = parentCache.get(key);
@@ -2730,7 +2589,7 @@ async function fetchParentMessageCached(token, groupId, channelId, parentId, fet
2730
2589
  return cached.message;
2731
2590
  }
2732
2591
  if (cached) parentCache.delete(key);
2733
- const message = await fetchParent(token, groupId, channelId, parentId);
2592
+ const message = await require_reaction_types.fetchChannelMessage(token, groupId, channelId, parentId, deadline);
2734
2593
  const expiresAt = resolveParentCacheExpiresAt(Date.now());
2735
2594
  if (expiresAt !== void 0) touchLru(parentCache, key, {
2736
2595
  message,
@@ -2840,7 +2699,7 @@ async function resolveMSTeamsThreadContext(params) {
2840
2699
  const [parentResult, repliesResult] = await require_resolve_allowlist.withMSTeamsRequestDeadline({
2841
2700
  deadline,
2842
2701
  label: "MS Teams thread history",
2843
- work: () => Promise.allSettled([fetchParentMessageCached(graphToken, teamAadGroupId, params.conversationId, threadParentId, (token, groupId, requestedChannelId, messageId) => require_reaction_types.fetchChannelMessage(token, groupId, requestedChannelId, messageId, deadline)), require_reaction_types.fetchThreadReplies(graphToken, teamAadGroupId, params.conversationId, threadParentId, 50, deadline)])
2702
+ work: () => Promise.allSettled([fetchParentMessageCached(graphToken, teamAadGroupId, params.conversationId, threadParentId, deadline), require_reaction_types.fetchThreadReplies(graphToken, teamAadGroupId, params.conversationId, threadParentId, deadline)])
2844
2703
  });
2845
2704
  const parentMsg = parentResult.status === "fulfilled" ? parentResult.value : void 0;
2846
2705
  const replies = repliesResult.status === "fulfilled" ? repliesResult.value : [];
@@ -3540,9 +3399,6 @@ async function runMSTeamsFeedbackInvokeHandler(context, deps) {
3540
3399
  }
3541
3400
  //#endregion
3542
3401
  //#region extensions/msteams/src/file-consent-invoke.ts
3543
- /**
3544
- * Handle fileConsent/invoke activities for large file uploads.
3545
- */
3546
3402
  async function handleMSTeamsFileConsentInvoke(context, log) {
3547
3403
  const expiredUploadMessage = "The file upload request has expired. Please try sending the file again.";
3548
3404
  const activity = context.activity;
@@ -3634,7 +3490,7 @@ async function handleMSTeamsFileConsentInvoke(context, log) {
3634
3490
  async function runMSTeamsFileConsentInvokeHandler(context, log) {
3635
3491
  try {
3636
3492
  await require_conversation_store_state.withRevokedProxyFallback({
3637
- run: async () => await handleMSTeamsFileConsentInvoke(context, log),
3493
+ run: () => handleMSTeamsFileConsentInvoke(context, log),
3638
3494
  onRevoked: async () => true,
3639
3495
  onRevokedLog: () => {
3640
3496
  log.debug?.("turn context revoked during file consent invoke; skipping delayed response");
@@ -3849,23 +3705,22 @@ const STORE_KEY_VERSION_PREFIX = "v2:";
3849
3705
  function makeMSTeamsSsoTokenStoreKey(connectionName, userId) {
3850
3706
  return `${STORE_KEY_VERSION_PREFIX}${(0, node_crypto.createHash)("sha256").update(JSON.stringify([connectionName, userId])).digest("hex")}`;
3851
3707
  }
3852
- function createMSTeamsSsoTokenStoreFs(params) {
3708
+ function createMSTeamsSsoTokenStoreFs() {
3853
3709
  const tokenStore = require_runtime.getMSTeamsRuntime().state.openKeyedStore({
3854
3710
  namespace: MSTEAMS_SSO_TOKENS_NAMESPACE,
3855
- maxEntries: MSTEAMS_MAX_SSO_TOKENS,
3856
- env: require_conversation_store_state.resolveMSTeamsSqliteStateEnv(params)
3711
+ maxEntries: MSTEAMS_MAX_SSO_TOKENS
3857
3712
  });
3858
3713
  return {
3859
3714
  async get({ connectionName, userId }) {
3860
3715
  return await tokenStore.lookup(makeMSTeamsSsoTokenStoreKey(connectionName, userId)) ?? null;
3861
3716
  },
3862
3717
  async save(token) {
3863
- await require_conversation_store_state.withMSTeamsSqliteMutationLock(params, SSO_TOKEN_MUTATION_KEY, async () => {
3718
+ await require_conversation_store_state.withMSTeamsSqliteMutationLock(SSO_TOKEN_MUTATION_KEY, async () => {
3864
3719
  await tokenStore.register(makeMSTeamsSsoTokenStoreKey(token.connectionName, token.userId), require_conversation_store_state.toPluginJsonValue({ ...token }));
3865
3720
  });
3866
3721
  },
3867
3722
  async remove({ connectionName, userId }) {
3868
- return require_conversation_store_state.withMSTeamsSqliteMutationLock(params, SSO_TOKEN_MUTATION_KEY, () => tokenStore.delete(makeMSTeamsSsoTokenStoreKey(connectionName, userId)));
3723
+ return require_conversation_store_state.withMSTeamsSqliteMutationLock(SSO_TOKEN_MUTATION_KEY, () => tokenStore.delete(makeMSTeamsSsoTokenStoreKey(connectionName, userId)));
3869
3724
  }
3870
3725
  };
3871
3726
  }
@@ -3959,10 +3814,6 @@ async function monitorMSTeamsProvider(opts) {
3959
3814
  const cleanAllowEntries = (entries) => entries?.map((entry) => cleanAllowEntry(entry)).filter((entry) => entry && entry !== "*") ?? [];
3960
3815
  const isMutableUserEntry = (entry) => !isStableUserId(entry) && !/^accessGroup:/i.test(entry) && !require_resolve_allowlist.looksLikeMSTeamsConversationId(require_resolve_allowlist.normalizeMSTeamsConversationId(entry));
3961
3816
  const resolveAllowlistUsers = async (label, entries) => {
3962
- if (entries.length === 0) return {
3963
- additions: [],
3964
- unresolved: []
3965
- };
3966
3817
  const resolved = await require_resolve_allowlist.resolveMSTeamsUserAllowlist({
3967
3818
  cfg,
3968
3819
  entries